我正在尝试使用std::thread
4.9.1(std::bind
)编译boost::asio
,g++
和-std=c++11
的简单测试程序。
但是,当我使用std::bind
时,在创建新线程时,它不会编译。另一方面,当我切换到boost::bind
时,一切都很好。
以下是代码:
#include <iostream>
#include <memory>
#include <thread>
#include <functional>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
int main(int argc, char* argv[])
{
boost::asio::io_service ioService;
std::unique_ptr<std::thread> t;
t.reset(new std::thread(std::bind(&boost::asio::io_service::run, &ioService)));
//t.reset(new std::thread(boost::bind(&boost::asio::io_service::run, &ioService)));
return 0;
}
这是错误:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:12:80: error: no matching function for call to ‘bind(<unresolved overloaded function type>, boost::asio::io_service*)’
t.reset(new std::thread(std::bind(&boost::asio::io_service::run, &ioService)));
^
test.cpp:12:80: note: candidates are:
In file included from /usr/include/c++/4.9/memory:79:0,
from test.cpp:2:
/usr/include/c++/4.9/functional:1623:5: note: template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__or_<std::is_integral<typename std::decay<_Tp>::type>, std::is_enum<typename std::decay<_Tp>::type> >::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...)
bind(_Func&& __f, _BoundArgs&&... __args)
^
/usr/include/c++/4.9/functional:1623:5: note: template argument deduction/substitution failed:
test.cpp:12:80: note: couldn't deduce template parameter ‘_Func’
t.reset(new std::thread(std::bind(&boost::asio::io_service::run, &ioService)));
^
In file included from /usr/include/c++/4.9/memory:79:0,
from test.cpp:2:
/usr/include/c++/4.9/functional:1650:5: note: template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...)
bind(_Func&& __f, _BoundArgs&&... __args)
^
/usr/include/c++/4.9/functional:1650:5: note: template argument deduction/substitution failed:
test.cpp:12:80: note: couldn't deduce template parameter ‘_Result’
t.reset(new std::thread(std::bind(&boost::asio::io_service::run, &ioService)));
^
我错过了什么?
答案 0 :(得分:12)
错误消息表明std::bind()
无法确定要使用哪个io_service::run()
重载:
std::size io_service::run();
std::size io_service::run(boost::system::error_code&);
对于这种特殊情况,Boost.Bind没有问题,但它确实为binding an overloaded functions提供了一些故障排除。它建议铸造:
std::bind(
static_cast<std::size_t (boost::asio::io_service::*)()>(&boost::asio::io_service::run),
&ioService);
或使用临时变量:
std::size_t (boost::asio::io_service::*run)() = &boost::asio::io_service::run;
std::bind(run, &ioService);
std::bind()
而非boost::bind()
需要显式强制转换的原因是实现细节。如果对bind()
的调用的arity没有对被绑定的函数类型设置约束,那么重载函数将需要显式转换。
例如,考虑使用可变参数模板的情况:
template<class F, class... BoundArgs>
unspecified std::bind(F&& f, BoundArgs&&... bound_args);
如果选择了最匹配的std::bind()
重载,则std::bind()
的调用对F
没有任何限制。由于F
可能是以下任何一种:
std::size_t (boost::asio::io_service::*)()
std::size_t (boost::asio::io_service::*)(boost::system::error_code&)
表达式&boost::asio::io_service::run()
含糊不清。
另一方面,Boost.Bind是用重载函数实现的,其中对boost::bind()
的调用的arity对被绑定函数的arity设置了约束。它的接口synopsis列出了以下值得注意的重载:
// 2 args: member-to-function (arity:0), instance
template <class R, class T, class A1>
unspecified bind(R (T::*f)(), A1 a1);
// 3 args: member-to-function (arity:1), instance, arg1
template <class R, class T, class B1, class A1, class A2>
unspecified bind(R (T::*f)(B1), A1 a1, A2 a2);
请注意boost::bind()
有:
因此,在致电时:
boost::bind(&boost::asio::io_service::run, &ioService)
潜在匹配的boost::bind()
重载具有2的arity,因此指向成员的函数必须是arity为0的函数类型。因为{的集合中只有一个函数{1}}重载的arity为0,调用不明确。
答案 1 :(得分:9)
基于错误消息boost::asio::io_service::run
过载或成员模板,std::bind()
无法确定要使用的过载或实例化。你需要使用这样的东西,在取得地址时推断出合适的类型,例如,
static_cast<std:size_t (boost::asio::io_service::*)()>(&boost::asio::io_service::run)
关键问题是,取boost::asio::io_service::run
的地址会导致成员函数有两种选择,但在获取地址时,无法确定使用哪一种。只有在使用成员函数时,才会明确表示不使用其他参数的版本。但是,地址运算符不会产生过载集。
为了推断出需要哪个重载,std::bind()
需要提供一个自身的重载,它具有适当的类型作为其第一个参数。但是,我认为它无法确定应该是什么类型。我不知道它与std::boost::bind()
的实际效果如何!我可以想象boost::bind()
对于没有参数的成员函数有特殊的重载,可能还有boost::error_code
的一个,但我真的不知道这会有什么帮助。
但是使用lambda函数可能更容易:
std::thread t([&](){ ioService.run(); });
t.join(); // without a joining or detaching terminate() is called
答案 2 :(得分:1)
理解此错误的关键是unresolved overloaded function type
部分
这意味着编译器无法确定要使用哪个重载版本的boost::asio::io_service::run
。
在the docs中查看有两个版本,您想要使用std::size_t run()
。要将此信息传达给编译器,我们需要static_cast
函数指针指向重载变量的显式类型,这里std:size_t (boost::asio::io_service::*)()
因此我们写static_cast<std::size_t (boost::asio::io_service::*)(void)>(&boost::asio::io_service::run)
代替&boost::asio::io_service::run
完整代码如下所示
boost::asio::io_service ioService;
std::unique_ptr<std::thread> t;
t.reset(new std::thread(std::bind(
static_cast<std::size_t(boost::asio::io_service::*)(void)>(&boost::asio::io_service::run),
&ioService
)));
答案 3 :(得分:1)
Boost Bind支持绑定为绑定成员函数的this参数的智能指针。
这是std :: bind和boost :: bind之间相当大的(也是很棒的)差异。
Boost Asio一直推广模式¹,它严重依赖绑定到shared_pointer<T>
,其中T
可以是异步IO上下文中具有“神奇管理”生命周期的任何东西,例如connection
, client
,session
,transfer
等。
当然c ++ 11 lambdas可以直接支持(通过复制捕获共享指针)。
¹例如