相互递归的

Mutually recursive lambdas

本文关键字:递归      更新时间:2023-10-16

这是基于boost::asio示例的boost::asio udp echo演示。

使用c++ lambda的这个版本的肉小于boost示例的一半大小,但是gcc告诉我receivedrecv_from中不可见。

不得不以一种更冗长的方式写这篇文章,我感到很痛苦。有什么c++大师能教我一个定义相互递归lambda的技巧吗?

class server {
public:
  server(io_service& io_service, short port)
    : socket_(io_service, udp::endpoint(udp::v4(), port)) {
    auto recv_from = [&,received]() {
      socket_.async_receive_from(buffer(data_, max_length), sender_endpoint_,
                                 received);
    };
    auto received = [&,recv_from](const error_code& error, size_t bytes_transferred) {
      if (!error && bytes_transferred > 0) {
        socket_.async_send_to(buffer(data_, bytes_transferred), sender_endpoint_,
                              [&](const error_code&, size_t) {
                                recv_from();
                              });
      } else {
        recv_from(); // loop
      }
    };
    recv_from();
  }
private:
  udp::socket socket_;
  udp::endpoint sender_endpoint_;
  enum { max_length = 1024 };
  char data_[max_length];
};

编辑,解决方案:我需要添加这个:

std::function<void(const error_code&, size_t)> received;

使类型推断引擎更容易(我被Haskell编程宠坏了)

回答我自己的问题:

实际上我的代码至少有三个问题。

  1. 我已经小心地 receivedrecv_from复制到相应的闭包中,以便在构造函数超出作用域时它们可用。不幸的是,闭包与构造函数同时超出作用域。因此,[&, xxx]xxx的复制是没有意义的。

  2. 至少(?)一个lambda的类型必须是固定的,以取悦类型推理引擎。

  3. 但这并不能解决第一个问题。为了解决生命周期问题,我应该将闭包对象存储在server对象中。

所以我认为这是接近我需要做的:

class server {
 public:
   server(io_service& io_service, short port)
     : socket_(io_service, udp::endpoint(udp::v4(), port)) {
    recv_from = [&]() {
       socket_.async_receive_from(buffer(data_, max_length), sender_endpoint_,
                                 received);
    };
    received = [&](const error_code& error, size_t bytes_transferred) {
      if (!error && bytes_transferred > 0) {
        socket_.async_send_to(buffer(data_, bytes_transferred), sender_endpoint_,
                              [&](const error_code&, size_t) {
                                recv_from();
                              });
      } else {
        recv_from(); // loop
      }
    };
    recv_from();
  }
private:
  udp::socket socket_;
  udp::endpoint sender_endpoint_;
  std::function<void(const error_code&, size_t)> received;
  std::function<void()> recv_from;
  enum { max_length = 1024 };
  char data_[max_length];
};