c++ 当typename是模板化基类时的模板类定义

eqqqjvef  于 2023-04-01  发布在  其他
关注(0)|答案(1)|浏览(125)

我正在实现一个简单的服务器后端,它可以与tcp和unix套接字一起工作。
下面是listener块:

static asio::awaitable<void> listener() {
    const auto executor = co_await asio::this_coro::executor;
    asio::local::stream_protocol::acceptor acceptor(executor, asio::local::stream_protocol::endpoint(socket_file_));

    for (;;) {
        auto socket = co_await acceptor.async_accept(asio::use_awaitable);
        ...

之后,通过使用此socket创建Session类的示例来初始化会话。
在这种情况下,socket的类型为asio::local::stream_protocol::socket,但在tcp情况下,类型为asio::ip::tcp::socket
它们都有一个基类asio::basic_stream_socket,我想实现一个通用的Session类:

template <typename Protocol, typename Executor>
class Session : public std::enable_shared_from_this<Session<Protocol, Executor>> {
    using Socket = asio::basic_stream_socket<Protocol, Executor>;

public:
    explicit Session(Socket sock) : socket_(std::move(sock)) {}

    void start() {
        co_spawn(socket_.get_executor(),
                 [self = this->shared_from_this()] { return self->reader(); },
                 asio::detached);
    }

private:
    Socket socket_;

    asio::awaitable<void> reader() {
        ...

在这个实现中,我必须在listener方法中显式地指定类型ProtocolExecutor

std::make_shared<Session<asio::local::stream_protocol, asio::any_io_executor>>(std::move(socket))->start();

std::make_shared<Session<decltype(socket)::protocol_type, decltype(socket)::executor_type>>(std::move(socket))->start();

看起来累赘和多余的东西。
有什么方法可以优化Session类模板定义吗?

hc2pp10m

hc2pp10m1#

作为一个免责声明,我对boost asio的异步会话一无所知,但是如果我正确理解了你的问题,你想简化对你的Session类的shared_ptr的创建,而不必写出复杂的模板参数。
一般来说,你可以使用一个模板化的自由工厂函数create_session来实现这一点,它可以从传入的参数中推导出它的模板参数,如下所示:

#include <memory>

//********************** my very own boost asio implementation **********************//

template <typename Protocol, typename Executor>
struct asio_basic_stream_socket{
    using protocol_type = Protocol;
    using executor_type = Executor;
};

template <typename Protocol, typename Executor>
struct asio_local_stream_protocol_socket : asio_basic_stream_socket<Protocol, Executor> {};

template <typename Protocol, typename Executor>
struct asio_ip_tcp_socket : asio_basic_stream_socket<Protocol, Executor> {};

//********************** Session **********************//

template <typename Protocol, typename Executor>
class Session : public std::enable_shared_from_this<Session<Protocol, Executor>> 
{
public:
    using Socket = asio_basic_stream_socket<Protocol, Executor>;

    template <typename S>
    friend auto create_session(S);
private:
    Session(Socket){}
};

template <typename Socket>
auto create_session(Socket s)
{
    using P = typename Socket::protocol_type;
    using E = typename Socket::executor_type;
    using S = Session<P,E>;
    return std::shared_ptr<S>(new S(std::move(s)));
}

//********************** Usage **********************//

int main()
{
    asio_local_stream_protocol_socket<int, bool> x;
    auto session_ptr_x = create_session(x);

    asio_ip_tcp_socket<std::string, double> y;
    auto session_ptr_y = create_session(x);
}

一些注意事项:

  • create_session的主体中仍然有一点模板混乱,但这被很好地隐藏了起来。
  • 至少为了这个最小的例子,Session不需要从std::enable_shared_from_this导出。
  • 在示例中,Session的构造函数是私有的。这是基于Session示例只能通过工厂函数创建的假设。当然,这不是必需的。

https://godbolt.org/z/qExz4WzKn

相关问题