I use a function template to load a std::bind obj, my code:
#include <iostream>
#include <functional>
template<typename RT_, typename ...Args>
void installCallback(const char name[], const std::function<RT_(Args...)> &func)
{
}
int add(int a, int b)
{
return a + b;
}
int main(int argc, char *argv[])
{
installCallback("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2));
installCallback<int, int, int>("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2));// didn't work either
// this work well
std::function<int(int, int)> fun = std::bind(add, std::placeholders::_1, std::placeholders::_2);
installCallback("add02", fun);
return 0;
}
, I got this error:
/home/tong/Documents/awesome_auto_drive/awe_auto/sample/module/main.cpp:20:90: error: no matching function for call to 'installCallback(const char [6], std::_Bind_helper<false, int (&)(int, int), const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type)' 20 | installCallback("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2)); | ^ $./main.cpp:6:6: note: candidate: 'template<class RT_, class... Args> void installCallback(const char*, std::function<_Res(_ArgTypes...)>&&)' 6 | void installCallback(const char name[], std::function<RT_(Args...)> &&func) | ^~~~~~~~~~~~~~~ $./main.cpp:6:6: note: template argument deduction/substitution failed: $./main.cpp:20:90: note: 'std::_Bind_helper<false, int (&)(int, int), const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type' {aka 'std::_Bind<int (*(std::_Placeholder<1>, std::_Placeholder<2>))(int, int)>'} is not derived from 'std::function<_Res(_ArgTypes...)>' 20 | installCallback("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2)); | ^ sample/module/CMakeFiles/module.dir/build.make:62: recipe for target 'sample/module/CMakeFiles/module.dir/main.cpp.o' failed make[2]: *** [sample/module/CMakeFiles/module.dir/main.cpp.o] Error 1 CMakeFiles/Makefile2:2665: recipe for target 'sample/module/CMakeFiles/module.dir/all' failed make[1]: *** [sample/module/CMakeFiles/module.dir/all] Error 2 Makefile:129: recipe for target 'all' failed make: *** [all] Error 2
who can tell me, what happened?
You are running into template function argument deduction rules. std::bind
does not return a std::function
, and your passed int
for Args...
is only a prefix to Args...
. So C++ attempts to deduce the rest of Args...
and fails with that error.
A quick fix is
template<class Sig>
void installCallback(const char name[], const std::function<Sig> &func)
then
installCallback<int(int, int)>
this leaves the body of installCallback
bereft of Args...
.
Now,
installCallback("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2));
cannot work, because bind
(a) is not a std function, and (b) doesn't know what its argument types are.
It is also pointless here.
installCallback("add01", add);
is logically equivalent and less filled with noise. It still won't compile; however in c++17 this will:
installCallback("add01", std::function(add));
due to deduction guides. The bind version will not.
As a general rule, if you are using std bind, instead use a lambda. In c++11 lambdas can replace 95% of bind usage mechanically, and in c++14 it becomes 99.9%, with the remaining 0.1% being features of bind you probably shouldn't be using and don't know exists (and usually won't until it breaks your code in surprising ways; passing std bind to std bind).
I like the answer from @yakk-adam-nevraumont. I think it is very clear and explains things aptly; the superior answer so far so I upvoted it. The only other contribution I can make is that I was able to arrive at a similar conclusion (deduction rules not yielding std::function
) using the boost library to de-mangle the printed type names of each expression. See code below modified from the sample @JoeT provided and working snippet here .
You'll notice the deduced type of fun1
is different than the explicit type of fun2
.
#include <functional>
#include <iostream>
#include <typeinfo>
#include <boost/core/demangle.hpp>
template<typename RT_, typename ...Args>
void installCallback(const char name[], const std::function<RT_(Args...)> &func)
{
}
int add(int a, int b)
{
return a + b;
}
int main(int argc, char *argv[])
{
auto fun1 = std::bind(add, std::placeholders::_1, std::placeholders::_2);
std::function<int(int, int)> fun2 = std::bind(add, std::placeholders::_1, std::placeholders::_2);
char const* name = typeid( fun1 ).name();
// Outputs: std::_Bind<int (*(std::_Placeholder<1>, std::_Placeholder<2>))(int, int)>
std::cout << boost::core::demangle(typeid(fun1).name()) << std::endl;
// Outputs: std::function<int (int, int)>
std::cout << boost::core::demangle(typeid(fun2).name()) << std::endl;
return 0;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.