[英]std::function and std::bind: how to load a std::bind with a function template
我使用 function 模板來加載 std::bind obj,我的代碼:
#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;
}
,我得到了這個錯誤:
/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
誰能告訴我,發生了什么?
您遇到了模板 function 參數推導規則。 std::bind
不返回std::function
,並且您為Args...
傳遞的int
只是Args...
... 的前綴。 所以 C++ 試圖推斷出Args...
並因該錯誤而失敗。
快速修復是
template<class Sig>
void installCallback(const char name[], const std::function<Sig> &func)
然后
installCallback<int(int, int)>
這使得installCallback
的主體失去了Args...
現在,
installCallback("add01", std::bind(add, std::placeholders::_1, std::placeholders::_2));
無法工作,因為bind
(a) 不是 std function,並且 (b) 不知道它的參數類型是什么。
在這里也毫無意義。
installCallback("add01", add);
在邏輯上是等價的,並且較少充滿噪音。 它仍然無法編譯; 但是在c++17這將:
installCallback("add01", std::function(add));
由於扣除指南。 綁定版本不會。
作為一般規則,如果您使用標准綁定,請改用 lambda。 在c++11 中,lambda 可以機械地替換 95% 的綁定使用,在c++14中,它變為 99.9%,剩下的 0.1% 是綁定的特性,你可能不應該使用並且不知道存在(通常直到它存在)以令人驚訝的方式破壞您的代碼;將 std 綁定傳遞給 std 綁定)。
我喜歡@yakk-adam-nevraumont 的回答。 我認為它非常清楚並且恰當地解釋了事情; 到目前為止最好的答案,所以我贊成它。 我唯一能做出的其他貢獻是,我能夠得出一個類似的結論(推導規則不會產生std::function
)使用 boost 庫來消除每個表達式的打印類型名稱。 請參閱下面從提供的示例@JoeT 修改的代碼和此處的工作片段。
您會注意到fun2
的推導類型與fun1
的顯式類型不同。
#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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.