I have the following problem. When I try to compile the following code
template< typename T >
T func( T t)
{
return t;
}
template< size_t N, typename T >
void foo( std::function< T(T) > func )
{
// ...
}
int main()
{
foo<3>( func<float> );
return 0;
}
I get the error:
no matching function for call to 'foo'
foo<3>( func<float> );
^~~~~~
/Users/arirasch/WWU/dev/xcode/tests/tests/main.cpp:18:10: note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-1)>' against 'float (*)(float)'
void foo( std::function< T(T) > func )
However, when I fix it to
template< typename T >
T func( T t)
{
return t;
}
template< size_t N, typename T >
void foo( std::function< T(T) > func )
{
// ...
}
int main()
{
std::function< float(float) > input_func = func<float>;
foo<3>( input_func );
return 0;
}
i.e., when I declare the input function of foo
explicitly as std::function< float(float) >
, the compilation can be done successfully.
Does anyone know how I can fixe my code alternatively so that I can simply write something like foo<3>( func<float> );
(according to my first code example) instead of
std::function< float(float) > input_func = func<float>;
foo<3>( input_func );
where the type of input_func
must be explicitly stated?
Many thanks in advance.
Type deduction does not work in your case simply because it cannot be deduced. Type deduction is, in most cases, a simple match with types and other template parameters. There is however some dark corner of C++ that deal with deduction that has some funky rules, but I won't go into it for this answer.
This is an example where the compiler can deduce template arguments:
template<typename T>
void test(std::vector<T>);
test(std::vector<int>{1, 2, 3, 4, 5, 6});
This is easy for the compiler. It need a std::vector
of T
. You give it a std::vector
of int
. T
must be int
.
However, in your case, There is a lot more stuff happening:
template<typename T>
void test(std::function<T(T)>);
int someFunc(int);
test(someFunc);
The compiler can't do the match. Try for yourself: Give me a T
that will make those two types equal: int(*)(int)
to std::function<T(T)>
. Indeed, there is no possible T
that can make those two type to be the same, whereas the vector version was an easy match.
You will say to me: "but... a pointer to a function is convertible to a std::function you silly!" Yeah, it is convertible, indeed. But before any conversion, the compiler has to find what T
is. Without T
, you make the conversion from a pointer to function to what class? Many class? Try to match every T
? There is multiple possibility where your function would be convertible.
How can you make this work? Forget the std::function
. Just receive T
.
template<typename T>
T func(T t) {
return t;
}
template<size_t N, typename T>
void foo(T func) {
// ...
}
int main()
{
foo<3>( func<float> );
return 0;
}
Notice how this example works well. You have no conversion, no std::function
thingy and can work with any callable you can possibly imagine!
Are you worried about accepting any type? No worry here! Parameter types are a bad way to express what a template can do with received parameters anyway. You should restrict it with an expression. That expression will tell others how you will use T
and what interface T
need to have. btw, we call that sfinae:
template<size_t N, typename T>
auto foo(T func) -> decltype(void(func(std::declval<int>()))) {
// ...
}
In this example, you restrict func
to be callable with a int
and still return void
.