具有异步操作的std :: function回调

时间:2015-04-07 19:05:10

标签: c++ c++11 asynchronous callback std-function

我想在包装类中使用std :: functions作为回调参数。 该类包装了一个允许异步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 capture子句中正确捕获回调处理程序,以便我可以在(3)中调用它?

附注: 在所有异步操作完成之前,MyConnection的客户端实例永远不会超出范围!

1 个答案:

答案 0 :(得分:3)

std::functionmove来说很便宜,因此按价值取值是可以接受的。按&&拍摄大多没有意义,因为最多可以保存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)}
);

,其缺点是将代码从内联移到了外线。