Reputation: 73
I've got a functor f, which takes a function func and a parameter t of the same type as func. I cannot pass g to f because of compilation error (no matching function for call to f(int&, void (&)(int&))
). If g would take non-reference parameter g(int s), compilation finishes. Or if I manually specify template parameter f<int&>(i, g)
, compilation also finishes.
template<typename T>
void f(T t, void (*func)(T)) {}
void g(int& s) {}
int main(int, char*[])
{
int i = 7;
f(i, g); // compilation error here
return 0;
}
How can I get deduction to work?
Upvotes: 4
Views: 1489
Reputation: 507085
The problem is that if in a template one of its function parameters is not a reference type before deduction starts, that parameter will never deduce to a reference type. So in the deduction on the left side, T
yields int
, but on the deduction on the right side, T
yields int&
. That's a mistmatch and the compiler complains.
The best is to make the function parameter the same type as the parameter type of the function pointer:
template<typename T> struct identity { typedef T type; };
template<typename T>
void f(typename identity<T>::type t, void (*func)(T)) {}
By using identity<T>::type
, you disable deduction on the left side. Once the T
was determined at the right side, T
is sustituted into the left side and yields the final parameter type.
One guy proposed to take the right side as a template parameter - this is a good thing since it can then accept function objects with operator()
overloaded. But you then face the problem of having to know whether it wants a reference or not. To solve it, boost
has reference_wrapper
(by the way, boost
also has the identity
template above).
template<typename T, typename F>
void f(T t, F func) {}
Now, if you want to pass a reference and not a copy, you can do that like this
int i;
f(boost::ref(i), some_function);
ref
returns a reference_wrapper object which is implicitly convertible to T&
. So if you call func(t)
, the t
is converted to the target reference automagically. If you don't want to pass a reference, just pass i
directly.
Upvotes: 5
Reputation: 35188
template<typename T>
void f(T t, void (*func)(T)) {}
The key thing here is that you used T
in both arguments. That means the types have to match exactly.
void g(int& s) {}
int i = 7;
f(i, g);
In your code, you pass an int
and a function taking an int&
to f()
. Those are different types but your template for f
expects two of the same type. The easiest fix, as others have suggested, is to make the function a template as well.
template <typename T, typename F>
void f(T t, F func)
{
func(t);
}
Upvotes: 1
Reputation: 41341
You can invoke the function like this:
f<int&>(i, g);
But now i will be passed by reference too.
In general, I'd make the function a template type too:
template <typename T, typename F>
void f(T t, F func)
{
func(t); //e.g
}
Upvotes: 6
Reputation: 5949
I think you need either:
void f(T t, void (*func)(T&)) {}
or:
void g(int s) {}
but I prefer:
template<typename T, typename T2>
void f(T t, T2 func) {}
as this will work with functions and functors.
Upvotes: 5