Template parameter deduction with function pointers and references [duplicate] - c++

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...

Related

Pass class with templated method as template parameter with GCC [duplicate]

This question already has answers here:
C++ template compilation error: expected primary-expression before ‘>’ token [duplicate]
(1 answer)
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 4 years ago.
Is it possible to pass object of a class with templated method as a template parameter under GCC? All search I conducted pointed me to questions regarding templated class, which is not applicable in my case.
Sample code:
#include <iostream>
class Foo
{
public:
template<typename T>
void print(const T& arg) const
{
std::cout << arg << std::endl;
}
};
template<typename A>
void print(const A& printer)
{
printer.print<int>(1);
}
int main()
{
Foo foo;
print<Foo>(foo);
return 0;
}
Compiling under MinGW.org GCC-6.3.0-1 I get the following results:
tmpl.cpp: In function 'void print(const A&)':
tmpl.cpp:16:19: error: expected primary-expression before 'int'
printer.print<int>(1);
^~~
tmpl.cpp:16:19: error: expected ';' before 'int'
VisualStudio compiles the same code cleanly, application works as expected. If I make print function not templated, so that is explicitly takes object of Foo it works as expected both compilers.
You need to use template keyword to tell that print is a template.
Inside a template definition, template can be used to declare that a dependent name is a template.
e.g.
template<typename A>
void print(const A& printer)
{
printer.template print<int>(1);
// ~~~~~~~~
}
print is a dependent name, it depends on the template parameter A. Before the template gets instantiated the compiler knows nothing about A; so you need to add the template keyword to tell the compiler that print is a template, then the < after the name print is valid; otherwise < will be treated as the operator< then cause the error.
You need the template keyword in order to specify that print() is a template, like this:
printer.template print<int>(1);

Why doesn't SFINAE select the const-reference-taking overload? [duplicate]

This question already has an answer here:
Does SFINAE apply to function bodies?
(1 answer)
Closed 4 years ago.
In this code
struct A {int commmon; int rare;};
struct B {int commmon;};
struct L {
template<class T>
int f(const T& t) {return t.commmon;}
template<class T>
int f(T& t) {return t.rare;}
};
void func() {
A a; B b; L l;
l.f(a);
l.f(B{});
l.f(b);
}
the final lines gives me the error
In instantiation of ‘int L::f(T&) [with T = B]’:
error: ‘struct B’ has no member named ‘rare’
But according to my understanding of SFINAE, the second overload should be ignored because of the substitution failure in the body. Why doesn't this happen?
EDIT: If I change the return type of the second overload to decltype(T::rare), it does what I want. So where does my SF need to happen to be NAE?
The least verbose way to fix that is to use an auto return type with a trailing return type on the more constraint overload:
struct L {
template <class T>
auto f(const T& t) {return t.commmon;}
template <class T>
auto f(T& t) -> decltype(t.rare) {return t.rare;}
};
The advantage of this approach is that the constraint is specified at a point where the compiler has already seen the function argument, allowing for a shorter notation than std::enable_if clauses in the declaration of template parameters:
#include <type_traits>
struct L {
template <class T>
int f(const T& t) {return t.commmon;}
template <class T, std::enable_if_t<std::is_same_v<std::decay_t<T>, A>, int> = 0>
int f(T& t) { return t.rare;}
};
Note further that the more constrained function won't be called when passing an rvalue argument. You might want to fix that by changing the function signatures to
template<class T /*, ... */>
int f(T&& t) { /* ... */ }
SFINAE does not apply to function bodies [temp.deduct/8]:
Only invalid types and expressions in the immediate context of the function type, its template parameter types, and its explicit-specifier can result in a deduction failure.
Template arguments are deduced before the function actually is instantiated. At the time the implementation is evaluated, the deduction has already occurred. So all that's relevant for deduction is the function signature, and from the existing ones, the non-const variant is fine to select.
If you want to apply get SFINAE applied depending on members existing, you have to do this within the function signature already. lubgr's answer reflects this nicely: The return type is decltype(t.rare); if T does not provide a rare member, the return type cannot be deduced and thus the overload is not considered during resolution.
Found two other answers dealing with the matter you might be interested in: C++11, compatible to pre-C++11

c++ template function error: template-id does not match any template declaration [duplicate]

This question already has answers here:
Templated Functions.. ERROR: template-id does not match any template declaration
(2 answers)
Closed 6 years ago.
I have the following code of function template in C++:
class UserHelpler{
public:
template <typename ValueType>
void createHelper(ValueType& value);
};
template<>
void UserHelpler::createHelper<int>(int* p_user)
{
}
When I build it, it shows the following error:
error: template-id 'createHelper<int>' for 'void UserHelper::createHelper(int*)'
does not match any template declaration
What is the problem and how to fix it?
The problem is that pointers and references are different things. Your template specialization has a signature which is incompatible with the template, as int* and int& are different types.
Probably, you need
createHelper<int>(int& p_user)
instead of
createHelper<int>(int* p_user)
Your template declaration requires your parameter to be of reference type, but in your specialization you provide a pointer instead, which doesn't match. Change your specialization to:
template<>
void UserHelpler::createHelper<int>(int& p_user)
Or alternatively change your template declaration to:
template <typename ValueType>
void createHelper(ValueType* value);

Templated function on templated subclass [duplicate]

This question already has answers here:
Workaround for template argument deduction in non-deduced context
(1 answer)
Nested template and parameter deducing [duplicate]
(1 answer)
Closed 8 years ago.
I'm having a bit of trouble trying to figure out why gcc cannot deduce the template arguments in the following code:
template <int N>
struct A {
template <int M>
struct B {
};
};
template <int N, int M>
void function(typename A<N>::template B<M> &b) {
// do stuff
}
int main() {
A<1>::B<2> b;
function(b);
}
Error:
$ g++ -std=c++11 -std=gnu++11 test.cpp
test.cpp: In function ‘int main()’:
test.cpp:19:12: error: no matching function for call to ‘function(A<1>::B<2>&)’
function(b);
^
test.cpp:19:12: note: candidate is:
test.cpp:13:6: note: template<int N, int M> void function(typename A<N>::B<M>&)
void function(typename A<N>::template B<M> &b) {
^
test.cpp:13:6: note: template argument deduction/substitution failed:
test.cpp:19:12: note: couldn't deduce template parameter ‘N’
function(b);
I leave this answer mainly because of the comments. The question has apparently been previously posted and answered.
But as a rule of thumb, for template deduction, in my experience use clang as replacement/alternative, it has much better error messages for such issues (like why template deduction failed).

Passing function template specializations to a variadic template function

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).