派生类型的成员

Member of derived type

考虑以下示例:

现在,我在 connection 中可以做的最简单的事情就是拥有一个 socket * 指针。 connection 然后可以在其构造函数中接受一个指针,一切都很好。但是,这里存在一个性能问题:每当我的 connection 对象想要与我的 socket 对象通信时,就会有一个需要时间的取消引用。

我想做的是让 socket 真正成为 connection 的成员。不要误会我的意思:我知道 socket 的不同特化可以有不同的大小,所以我不能简单地做这样的事情:socket my_pretty_socket;

我的想法

我想知道的是,如果下面的想法没有任何意义,为什么。

我有一组有限的 socket 可能的专业化。如果我构建一些 template any <typename base, typename... specializations> 会怎样:

通过这种方式,我可以将对象作为 connection 的成员放置到位,并且可以在节省内存事务的同时保留接口的所有优良属性。

  1. 这个想法很蠢吗?为什么?
  2. 是否已经有解决方案可以做到这一点?我相信我不会是唯一遇到这种问题的人。

根据问题和评论,我认为最好的办法是简单地放弃继承并使用 variant。该解决方案需要 boost、C++17 或带有变体 TS 实现的新式 compiler/standard 库,最好是 14。变体是一种存储多种类型之一的类型。它根据最大类型的大小将所有内容存储在堆栈中。

struct tcp {
  void do_stuff() const;
};

struct udp {
  void do_stuff() const;
};

using socket_type = std::variant<tcp,udp>;

void do_stuff(const socket_type& s) {
    visit([] (const auto& x) { x.do_stuff(); }, s);
}

enum class SocketKind { TCP, UDP };

template <class ... Args>
socket_type make_socket(SocketKind k, Args && args) {
    if (k == SocketKind::TCP) { return tcp(std::forward<Args>(args)...); }
    if (k == SocketKind::UDP) { return udp(std::forward<Args>(args)...); }  
}

您可以使用这样的工厂创建这些套接字,然后您可以在套接字对象上一般调用 do_stuff。所有内容都在线存储在内存中,并且将通过 switch-case 处理分派,如果您有少量套接字类型,这可能比 vtable 更快(但这只是猜测)。

(请注意,我使用可变 lambda 来编写 do_stuff,这只是简化了事情,但并不是真正需要的。您可以手动写出该访问者,因此您仍然可以使用此解决方案甚至C++03只要能用boost即可)。