简体   繁体   中英

std::function and std::bind: how to load a std::bind with a function template

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 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 lambdas can replace 95% of bind usage mechanically, and in 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM