std::function 异步操作的回调
std::function callbacks with asynchronous operations
我想在包装器 class 中使用 std::functions 作为回调参数。
class 包装了一个允许异步 TCP/IP 操作的库(实际上 boost::asio 但 boost::asio 和 TCP/IP 在这里都不重要,只是它具有异步操作)。
库函数允许我传递另一个回调函数对象,该对象在请求的操作完成时被异步调用。
根据异步操作的结果,我想调用客户端指定的回调或开始进一步的操作。
以下代码试图勾勒出我的意图。
using ConnectHandler = std::function<void(boost::system::error_code ec)>;
class MyConnection
{
public:
void Connect(ConnectHandler handler); // (1)
}
void MyConnection::Connect(ConnectHandler handler)
{
SomeLibrary::async_connect(...,
[handler](boost::system::error_code ec, ...) // (2)
{
//Depending on ec start a nested read/write operation.
//One way or another it finally invokes the callback
handler(ec); // (3)
});
}
客户端代码看起来像这样
MyConnection conn;
conn.Connect([](boost::system::error_code ec)
{
//check ec and start read/write operation
});
我的问题是:
在 (1) 中声明我的 Connect 方法的最佳方式是什么,f.e
void Connect(ConnectHandler handler);
void Connect(const ConnectHandler& handler);
void Connect(ConnectHandler&& handler);
并根据此如何在 (2) 的 lambda 捕获子句中正确捕获回调处理程序,以便我可以在 (3) 中调用它?
旁注:
在所有异步操作完成之前,MyConnection 的客户端实例永远不会超出范围!
std::function
比move
便宜,所以按值取值是可以接受的。拿 &&
基本上是没有意义的,充其量只能节省 move
。而且它强制调用者move
,而不是复制,也许调用者想要复制?
它们的复制成本并不低,因此您可以考虑在可调用对象中通过 move
捕获。
在 C++14 中,这很简单:
[handler=std::move(handler)]
作为捕获列表(通用捕获表达式)。
在 C++11 中,您需要编写一个自定义对象来执行此操作。
struct custom_work {
ConnectHandler handler;
void operator()(boost::system::error_code ec, ...) const {
//Depending on ec start a nested read/write operation.
//One way or another it finally invokes the callback
handler(ec); // (3)
}
};
然后
SomeLibrary::async_connect(...,
some_work{std::move(handler)}
);
它的缺点是将代码从内联移动到外联。
我想在包装器 class 中使用 std::functions 作为回调参数。 class 包装了一个允许异步 TCP/IP 操作的库(实际上 boost::asio 但 boost::asio 和 TCP/IP 在这里都不重要,只是它具有异步操作)。
库函数允许我传递另一个回调函数对象,该对象在请求的操作完成时被异步调用。 根据异步操作的结果,我想调用客户端指定的回调或开始进一步的操作。 以下代码试图勾勒出我的意图。
using ConnectHandler = std::function<void(boost::system::error_code ec)>;
class MyConnection
{
public:
void Connect(ConnectHandler handler); // (1)
}
void MyConnection::Connect(ConnectHandler handler)
{
SomeLibrary::async_connect(...,
[handler](boost::system::error_code ec, ...) // (2)
{
//Depending on ec start a nested read/write operation.
//One way or another it finally invokes the callback
handler(ec); // (3)
});
}
客户端代码看起来像这样
MyConnection conn;
conn.Connect([](boost::system::error_code ec)
{
//check ec and start read/write operation
});
我的问题是: 在 (1) 中声明我的 Connect 方法的最佳方式是什么,f.e
void Connect(ConnectHandler handler);
void Connect(const ConnectHandler& handler);
void Connect(ConnectHandler&& handler);
并根据此如何在 (2) 的 lambda 捕获子句中正确捕获回调处理程序,以便我可以在 (3) 中调用它?
旁注: 在所有异步操作完成之前,MyConnection 的客户端实例永远不会超出范围!
std::function
比move
便宜,所以按值取值是可以接受的。拿 &&
基本上是没有意义的,充其量只能节省 move
。而且它强制调用者move
,而不是复制,也许调用者想要复制?
它们的复制成本并不低,因此您可以考虑在可调用对象中通过 move
捕获。
在 C++14 中,这很简单:
[handler=std::move(handler)]
作为捕获列表(通用捕获表达式)。
在 C++11 中,您需要编写一个自定义对象来执行此操作。
struct custom_work {
ConnectHandler handler;
void operator()(boost::system::error_code ec, ...) const {
//Depending on ec start a nested read/write operation.
//One way or another it finally invokes the callback
handler(ec); // (3)
}
};
然后
SomeLibrary::async_connect(...,
some_work{std::move(handler)}
);
它的缺点是将代码从内联移动到外联。