Passing function template specializations to a variadic template function - c++

I have no problem passing the address of a function template specialization to a regular template function:
template <typename T>
void f(T) {}
template <typename A, typename B>
void foo(A, B) {}
int main()
{
foo(&f<int>, &f<float>);
}
However, when I try to pass the same specializations to a variadic template:
template <typename T>
void f(T) {}
template <typename... A>
void bar(A...) {}
int main()
{
bar(&f<int>, &f<float>);
}
I get the following compiler errors with GCC (I tried 4.6.1 and 4.7.0):
test.cpp: In function 'int main()':
test.cpp:9:27: error: no matching function for call to 'bar(<unresolved overloaded function type>, <unresolved overloaded function type>)'
test.cpp:9:27: note: candidate is:
test.cpp:5:6: note: template<class ... A> void bar(A ...)
test.cpp:5:6: note: template argument deduction/substitution failed:
Why am I getting these errors?

Looks like it might be a bug in GCC that is possibly fixed in GCC 4.6.2 (I say possibly because it's not exactly the same, but does involve getting the address of a variadic template function).

Related

C++ static template class member as friend template function default parameter

Why does using static template class member as friend template function default parameter give me compile error in c++? How to slove?
Here is the code:
#include <iostream>
template<typename T>
void func(T n);
template<typename T>
class MyClass
{
private:
static T statTemp;
public:
friend void func<>(T n);
};
template<typename T>
T MyClass<T>::statTemp(1);
template<typename T>
void func(T n = MyClass<T>::statTemp)
{
std::cout << n << std::endl;
}
int main()
{
func<int>();
}
On compile:
g++ -std=c++11 main.cpp
error: redeclaration of 'template<class T> void func(T)' may not have default arguments [-fpermissive]
void func(T n = MyClass<T>::statTemp)
^~~~
In function 'int main()':
error: no matching function for call to 'func<int>()'
func<int>();
^
note: candidate: 'template<class T> void func(T)'
void func(T n = MyClass<T>::statTemp)
^~~~
note: template argument deduction/substitution failed:
note: candidate expects 1 argument, 0 provided
func<int>();
^
visual studio 2017
C2672 "func": No matching overloaded function found.
The language does not allow default arguments for template functions to be added in later declarations of a function in the same scope.
The C++17 standard draft n4659 states :
11.3.6 Default arguments [dcl.fct.default]
...
4 For non-template functions, default arguments can be added in later declarations of a function in the same scope.
Since func is a template function, it is not permitted to add default arguments in later declarations of a func in the same scope.
So GCC correctly rejects this as such:
error: redeclaration of 'template<class T> void func(T)' may not have default arguments [-fpermissive]
void func(T n = MyClass<T>::statTemp)
I got your program to compile, however, I am honestly not sure what it is I really did. I can only take my intuition through it and do the best I can to explain what I just did:
#include <iostream>
template<typename T>
void func();
template<typename T>
class MyClass
{
private:
static T statTemp;
public:
friend void func<T>();
};
template<typename T>
T MyClass<T>::statTemp(1);
template<typename T>
void func()
{
T n = MyClass<T>::statTemp;
std::cout << n << std::endl;
}
int main()
{
func<int>();
}
First, I noticed your original funct(T n) you had declared this at the top of the file and it expected a T n to be passed into the function. In main, you do no such thing. So when you call func(T n) and pass nothing into the function, the compiler gets angry since it expects something to be passed in. Maybe what you can do, is overload the function in which calls another func(T n) where you pass it T n = MyClass<T>::statTemp;
Lastly, your friend void func<>() had no template type so the compiler was angry with that as well.
I hope that helps.

C++ template's template failed to compile

I've got this test program
#include<iostream>
#include<vector>
using namespace std;
template<template<class> class C, typename T>
void print(const C<T>& c){
for(auto& e : c)cout<<e<<endl;
}
int main(){
vector<int> v;
print(v);
return 0;
}
It fails to compile:
g++ m.cpp -std=c++11
m.cpp: In function ‘int main()’:
m.cpp:11:16: error: no matching function for call to ‘print(std::vector<int>&)’
print(v);
^
m.cpp:6:6: note: candidate: template<template<class> class C, class T> void print(const C<T>&)
void print(const C<T>& c){
^~~~~
m.cpp:6:6: note: template argument deduction/substitution failed:
m.cpp:11:16: note: template parameters of a template template argument are inconsistent with other deduced template arguments
print(v);
^
I changed print() signature from (const C& c) to (C& c), it still fails:
$ g++ m.cpp -std=c++11
m.cpp: In function ‘int main()’:
m.cpp:11:16: error: no matching function for call to ‘print(std::vector<int>&)’
print(v);
^
m.cpp:6:6: note: candidate: template<template<class> class C, class T> void print(C<T>&)
void print(C<T>& c){
^~~~~
m.cpp:6:6: note: template argument deduction/substitution failed:
m.cpp:11:16: note: template parameters of a template template argument are inconsistent with other deduced template arguments
print(v);
^
How to fix it?
Your compilation problem arises because your template template parameter C doesn't match the declaration of std::vector:
template<
class T,
class Allocator = std::allocator<T>
> class vector;
As you can see, std::vector has two template parameters, while your C has only one. But, note as well that the second parameter (class Allocator) has a default type argument. Since C++17, this is well-formed even the way you've written it, as it was added that template template parameters matching doesn't require specifying parameters for ones with default arguments like Allocator. But not all compilers are supporting this modification to the language spec -- see here live how Clang 6.0.0 refuses to compile your original snippet with C++17 enabled. Going for older versions of C++ (or just any version to date of Clang), this snippet is probably what you were aiming for:
template<template<class, class> class C, typename T, typename A>
void print(const C<T, A>& c){
for(auto& e : c)cout<<e<<endl;
}
As here you specify the correct template signature of the type (std::vector) you're later instantiating print() with.
This would work too, regardless of C++17:
template<template<class...> class C, typename T>
void print(const C<T>& c){
for(auto& e : c)cout<<e<<endl;
}
That said, note that, as vector<int> is already a fully instantiated type, this simpler version works just as well in the given scope of your snippet:
template<typename T>
void print(const T& c){
for(auto& e : c)cout<<e<<endl;
}
I changed print() signature from (const C& c) to (C& c), it still
fails:
This is probably the better practice in this case, as you're not modifying c inside of print(). However, this has nothing to do with your error.
std::vector contains two template parameters, while the template template parameter C is declared to contain only one. Anyway, your code would work fine with C++17; since C++17 (CWG 150), the default template arguments are allowed for a template template argument to match a template template parameter with fewer template parameters.
LIVE
Before C++17 you may apply parameter pack.
template<template<class...> class C, typename T>
void print(const C<T>& c){
for(auto& e : c)cout<<e<<endl;
}
LIVE

Partial specialization of variadic template member function

I'm struggling with specializations of member functions when they are templated using variadic template.
The following example specializes a whole class and it works fine:
template<typename... Args>
class C;
template<class T, typename... Args>
class C<T, Args...> { };
template<>
class C<> { };
int main() {
C<int, double> c{};
}
The following one does not, even though the idea behind it is exactly the same of the one above:
class F {
template<typename... Args>
void f();
};
template<class T, typename... Args>
void F::f<T, Args...>() { }
int main() {
}
I'm getting the following error and I don't understand what it's due to:
main.cpp:7:23: error: non-type partial specialization ‘f<T, Args ...>’ is not allowed
void F::f<T, Args...>() { }
^
main.cpp:7:6: error: prototype for ‘void F::f()’ does not match any in class ‘F’
void F::f<T, Args...>() { }
^
main.cpp:3:10: error: candidate is: template<class ... Args> void F::f()
void f();
^
Is there some constraints I'm not aware of when specializing function template?
G++ version is: g++ (Debian 5.2.1-23) 5.2.1 20151028
EDIT
By the way, the actual problem I'm getting from the real code is:
non-class, non-variable partial specialization ‘executeCommand<T, Args ...>’ is not allowed
Anyway, the reduced example is similar to the real one. I hope the errors are not completely unrelated.
You cannot partially specialize function templates; only explicit specialization is allowed.
You can get pretty much the same effect using overloading, especially if you use concepts such as tag dispatching.

Variadic template deduction using type alias

I have a program like this:
template<typename ...Args>
using Function = void(*)(Args *...);
template<typename ...Args>
void DoThing(Function<Args...> func) { }
void IntFunction(int *i) { }
int main(int argc, char *argv[]) {
DoThing(IntFunction);
}
When I run the program I get this error
$ clang++ -std=c++14 template.cpp
template.cpp:12:3: error: no matching function for call to 'DoThing'
DoThing(IntFunction);
^~~~~~~
template.cpp:7:6: note: candidate template ignored: substitution failure [with Args = int]
void DoThing(Function<Args...> func) { }
^
1 error generated.
But if I compile it using g++ I don't get any errors.
It appears that clang is having trouble deducing the variadic template parameters when used in a type alias. If I replace the variadic parameters with standard ones then I don't get the error anymore.
Which compiler is giving me the proper result? And why would I not be allowed to do this?
Can be reduced to
template <typename... T>
using funptr = void(*)(T...);
template <typename... T>
void f(funptr<T...>) {}
template void f(void(*)());
This is valid code; if we substitute funptr<T...> by the corresponding pack expansion, Clang suddenly doesn't complain anymore.
Reported as #25250.

Template parameter deduction with function pointers and references [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why are qualifiers of template arguments stripped when deducing the type?
Consider the following C++ code:
void f(int&);
template <typename T> void tpl(void (*)(T), T);
void bar(int& x)
{
tpl(&f, x);
}
Compilation using GCC 4.6.0 fails with the following error message:
fntpl.cpp: In function ‘void bar(int&)’:
fntpl.cpp:7:11: error: no matching function for call to ‘tpl(void (*)(int&), int&)’
fntpl.cpp:7:11: note: candidate is:
fntpl.cpp:3:46: note: template<class T> void tpl(void (*)(T), T)
If I state the template parameters explicitely (tpl<int&>(&f, x)), it works. Why doesn't template argument deduction work in this case?
Because these are fundamentally different
void f(int&);
and
void (*)(T)
the compiler has only deduced that T is int, so it looks for:
void f(int);
which is nothing like your intention, change the function pointer to this:
template <typename T> void tpl(void (*)(T&), T);
And the compiler will be happy...