为什么 boost::asio::io_service 不能用 std::bind 编译?
Why does boost::asio::io_service not compile with std::bind?
我正在尝试使用 g++
4.9.1 (-std=c++11
) 使用 std::thread
、std::bind
和 boost::asio
编译简单的测试程序。
但是,当我使用 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)));
^
我错过了什么?
根据错误消息 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
的地址会导致成员函数有两种选择,但在获取地址时无法确定使用哪一个。只有在使用成员函数时,才明确表示要使用不带附加参数的版本。但是,address-of 运算符不会产生重载集。
为了推断需要哪个重载,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
理解这个错误的关键是unresolved overloaded function type
部分
这意味着编译器无法确定要使用哪个 boost::asio::io_service::run
的重载版本。
在 the docs 中查找,看到有 2 个版本,您想使用 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
)));
Boost Bind 支持智能指针绑定为绑定成员函数的 this 参数。
这是 std::bind 和 boost::bind 之间的一个相当大(而且很棒)的区别。
Boost Asio 一直提倡在很大程度上依赖于绑定到 shared_pointer<T>
的模式¹,其中 T
可以是异步 IO 上下文中具有 "magically managed" 生命周期的任何东西,例如 connection
、client
、session
、transfer
等
当然,c++11 lambdas 可以直接支持相同的功能(通过复制捕获共享指针)。
¹ 例如
- boost asio deadline_timer async_wait(N seconds) twice within N seconds cause operation canceled
- Proper cleanup with a suspended coroutine
错误消息表明 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()
的调用的数量没有对被绑定函数的类型施加约束,那么重载函数将需要显式转换。
例如,考虑使用可变参数模板的情况:
template<class F, class... BoundArgs>
unspecified std::bind(F&& f, BoundArgs&&... bound_args);
When the best matching std::bind()
overload is being selected, the arity of the call to std::bind()
places no restrictions on 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()
的调用的数量限制了被绑定函数的数量。它的接口 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()
有:
- 元数为 2,指向成员函数的指针的元数为 0
- 元数为 3,指向成员函数的指针的元数为 1
因此,调用时:
boost::bind(&boost::asio::io_service::run, &ioService)
作为潜在匹配项的 boost::bind()
重载的元数为 2,因此指向成员函数的指针必须是元数为 0 的函数类型。因为集合中只有一个函数io_service::run()
个重载的元数为 0,调用没有歧义。
我正在尝试使用 g++
4.9.1 (-std=c++11
) 使用 std::thread
、std::bind
和 boost::asio
编译简单的测试程序。
但是,当我使用 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)));
^
我错过了什么?
根据错误消息 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
的地址会导致成员函数有两种选择,但在获取地址时无法确定使用哪一个。只有在使用成员函数时,才明确表示要使用不带附加参数的版本。但是,address-of 运算符不会产生重载集。
为了推断需要哪个重载,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
理解这个错误的关键是unresolved overloaded function type
部分
这意味着编译器无法确定要使用哪个 boost::asio::io_service::run
的重载版本。
在 the docs 中查找,看到有 2 个版本,您想使用 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
)));
Boost Bind 支持智能指针绑定为绑定成员函数的 this 参数。
这是 std::bind 和 boost::bind 之间的一个相当大(而且很棒)的区别。
Boost Asio 一直提倡在很大程度上依赖于绑定到 shared_pointer<T>
的模式¹,其中 T
可以是异步 IO 上下文中具有 "magically managed" 生命周期的任何东西,例如 connection
、client
、session
、transfer
等
当然,c++11 lambdas 可以直接支持相同的功能(通过复制捕获共享指针)。
¹ 例如
- boost asio deadline_timer async_wait(N seconds) twice within N seconds cause operation canceled
- Proper cleanup with a suspended coroutine
错误消息表明 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()
的调用的数量没有对被绑定函数的类型施加约束,那么重载函数将需要显式转换。
例如,考虑使用可变参数模板的情况:
template<class F, class... BoundArgs>
unspecified std::bind(F&& f, BoundArgs&&... bound_args);
When the best matching std::bind()
overload is being selected, the arity of the call to std::bind()
places no restrictions on 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()
的调用的数量限制了被绑定函数的数量。它的接口 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()
有:
- 元数为 2,指向成员函数的指针的元数为 0
- 元数为 3,指向成员函数的指针的元数为 1
因此,调用时:
boost::bind(&boost::asio::io_service::run, &ioService)
作为潜在匹配项的 boost::bind()
重载的元数为 2,因此指向成员函数的指针必须是元数为 0 的函数类型。因为集合中只有一个函数io_service::run()
个重载的元数为 0,调用没有歧义。