While exploring templates in C++, I stumbled upon the example in the following code:
#include <iostream>
#include <functional>
template <typename T>
void call(std::function<void(T)> f, T v)
{
f(v);
}
int main(int argc, char const *argv[])
{
auto foo = [](int i) {
std::cout << i << std::endl;
};
call(foo, 1);
return 0;
}
To compile this program, I am using the GNU C++ Compiler g++:
$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026
After compiling for C++11, I get the following error:
$ g++ -std=c++11 template_example_1.cpp -Wall
template_example_1.cpp: In function ‘int main(int, const char**)’:
template_example_1.cpp:15:16: error: no matching function for call to ‘call(main(int, const char**)::<lambda(int)>&, int)’
call(foo, 1);
^
template_example_1.cpp:5:6: note: candidate: template<class T> void call(std::function<void(T)>, T)
void call(std::function<void(T)> f, T v)
^~~~
template_example_1.cpp:5:6: note: template argument deduction/substitution failed:
template_example_1.cpp:15:16: note: ‘main(int, const char**)::<lambda(int)>’ is not derived from ‘std::function<void(T)>’
call(foo, 1);
^
(same for C++14 and C++17)
From the compiler error and notes I understand that the compiler failed to deduce the type of the lambda, since it cannot be matched against std::function.
Looking at previous questions (1, 2, 3, and 4) regarding this error, I am still confused about it.
As pointed out in answers from questions 3 and 4, this error can be fixed by explicitly specifying the template argument, like so:
int main(int argc, char const *argv[])
{
...
call<int>(foo, 1); // <-- specify template argument type
// call<double>(foo, 1) // <-- works! Why?
return 0;
}
However, when I use other types instead of int
, like double
, float
, char
, or bool
, it works as well, which got me more confused.
So, my questions are as follow:
- Why does it work when I explicitly specify
int
(and others) as the template argument? - Is there a more general way to solve this?