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

std::bind arguments not matching function parameters?

我正在尝试通过连接握手传递套接字,并使用 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*, std::function<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::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::executor>, boost::asio::io_context}]':

我的代码如下,错误似乎在给 boost::asio::acceptor.async_accept(socket, ...)std::bind 参数和 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, tcp::acceptor& acceptor, 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, acceptor, context));
    }

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

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

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

这段代码有很多问题。

共享指针似乎处于错误的抽象级别。您可能希望整个“连接”类型都具有共享生命周期,而不仅仅是套接字。在你的情况下,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 和绑定(你已经做了),注意 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

不再是完整的谎言:)