std::bind 参数与函数参数不匹配?

问题描述

我正在尝试通过连接握手传递套接字,并使用 std::bind 来执行此操作。我得到的编译问题(在一个连续块中,为了可读性我已经添加了空格)是:

'std::_Bind<_Functor(_Bound_args ...)>::_Bind(_Functor&&,_Args&& ...) 

[with _Args = {socket_state**,std::function<void(socket_state*)>&,boost::asio::basic_socket_acceptor<boost::asio::ip::tcp,boost::asio::executor>&,boost::asio::io_context&}; 

_Functor = void (*)(socket_state*,boost::asio::basic_socket_acceptor<boost::asio::ip::tcp>&,boost::asio::io_context&); 

_Bound_args = {socket_state**,std::function<void(socket_state*)>,boost::asio::executor>,boost::asio::io_context}]':

我的代码如下,错误出现在给 std::bindboost::asio::acceptor.async_accept(socket,...) 参数和 accept_new_client 方法的参数

    void start_server(std::function<void(socket_state*)>& func,tcp::acceptor& acceptor,boost::asio::io_context& context)
    {
        acceptor.listen();
        // Start client connection loop
        networking::wait_for_client(func,acceptor,context);
    }

    void wait_for_client(std::function<void(socket_state*)>& func,boost::asio::io_context& context)
    {
        boost::asio::ip::tcp::socket socket(context);

        // socket_state is its own class which links a particular socket with an ID and buffer data
        // it also holds a function to indicate which part of the connection handshake it needs to go to next
        socket_state* state = new socket_state(func,&socket);
        acceptor.async_accept(socket,std::bind(&networking::accept_new_client,state,func,context));
    }

    void accept_new_client(socket_state* state,std::function<void(socket_state*)>& func,boost::asio::io_context& context)
    {
            state->on_network_action(state);
            wait_for_client(func,context);
    }

看起来它们会匹配,但是您可以看到错误状态我的 std::bind 参数是 socket_state** 而不是 socket_state*,而 boost::asio::basic_socket_acceptor<boost::asio::ip::tcp,boost::asio::executor>& 而不是 {{1} }.

我也不知道“with _Args”与“_Bound_args”是什么。

解决方法

这段代码有很多问题。

共享指针似乎处于错误的抽象级别。您希望整个“连接”类型都具有共享生命周期,而不仅仅是套接字。就您而言,socket_state 是一个不错的选择。

无论如何,您的套接字是一个局部变量,您将一个陈旧的指针传递到 socket_state 内部。 Socket-state 看起来必然会泄露。

这样就永远行不通了。

接下来,绑定会急切地绑定所有参数,留下一个空签名。这不是 any overload 接受的 [没有双关语]。你需要匹配

让我们来看看 AcceptHandler。另外,我们不要绑定所有冗余参数(func 已经在 socket_stateremember,io_context` 被过度共享等)。

总的来说,您似乎需要树立信心,了解您所在的州。例如。这条线是有症状的:

state->on_network_action(state);

由于 on_network_actionsocket_state 的成员函数,因此永远不需要将 state 作为参数传递(它将是 this 隐式)。所有出现的 acceptorcontest 都是一样的。

演示

修复以上所有问题,使用 std::shared_ptr 和 bind(你已经这样做了),注意 placeholder::_1 接受 error_code 等)

Live On Coliru

#include <boost/asio.hpp>
#include <memory>
#include <iostream>

namespace ba = boost::asio;
using namespace std::chrono_literals;
using boost::system::error_code;
using ba::ip::tcp;

struct socket_state;
using Callback = std::function<void(socket_state&)>;

struct socket_state : std::enable_shared_from_this<socket_state> {
    Callback _callback;
    tcp::socket _socket;

    template <typename Executor>
    socket_state(Callback cb,Executor ex) : _callback(cb),_socket(ex)
    {
    }

    void on_network_action() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

struct networking {
    using StatePtr = std::shared_ptr<socket_state>;

    explicit networking(ba::io_context& ctx,Callback callback)
        : context(ctx),callback(callback)
    {
    }

    ba::io_context& context;
    tcp::acceptor acceptor {context,{{},8989}};
    Callback callback;

    void start_server()
    {
        std::cout << "start_server" << std::endl;
        acceptor.listen();
        wait_for_client(); // Start client connection loop
    }

    void stop_server() {
        std::cout << "stop_server" << std::endl;
        acceptor.cancel();
        acceptor.close();
    }

    void wait_for_client()
    {
        std::cout << "wait_for_client" << std::endl;
        // socket_state is its own class which links a particular socket with
        // an ID and buffer data it also holds a function to indicate which
        // part of the connection handshake it needs to go to next
        auto state =
            std::make_shared<socket_state>(callback,context.get_executor());

        acceptor.async_accept(state->_socket,std::bind(&networking::accept_new_client,this,std::placeholders::_1,state));
    }

    void accept_new_client(error_code ec,StatePtr state)
    {
        if (ec) {
            std::cout << "accept_new_client " << ec.message() << std::endl;
            return;
        }
        std::cout << "accept_new_client " << state->_socket.remote_endpoint()
                  << std::endl;
        state->on_network_action();
        wait_for_client();
    }
};

int main() {
    ba::io_context ctx;
    networking server(ctx,[](socket_state&) {
        std::cout << "This is our callback" << std::endl;
    });

    server.start_server();

    ctx.run_for(5s);

    server.stop_server();
    ctx.run();
}

有一些随机连接:

start_server
wait_for_client
accept_new_client 127.0.0.1:54376
void socket_state::on_network_action()
wait_for_client
accept_new_client 127.0.0.1:54378
void socket_state::on_network_action()
wait_for_client
accept_new_client 127.0.0.1:54380
void socket_state::on_network_action()
wait_for_client
accept_new_client 127.0.0.1:54382
void socket_state::on_network_action()
wait_for_client
stop_server
accept_new_client Operation canceled

注意版本发表评论

// socket_state is its own class which links a particular socket with
// an ID and buffer data it also holds a function to indicate which
// part of the connection handshake it needs to go to next

不再是完整的谎言:)