如何在编译时检测 class 在 C++17 中是否没有虚基?

How to detect whether a class has no virtual base in C++17 at compile time?

鉴于:

  1. 定义的类型T;
  2. 任何你想要的工具。

如何在编译时检测C++17中T是否没有虚基?

编辑:

其实我是在写一个type-erased container,在写获取copy ctor的代码的时候,发现只要一个class没有 virtual base 并且没有用户提供的复制构造函数,复制构造函数可以是指向诸如 std::memcpy.

之类的东西的指针

如果您使用 ,您 可能 能够根据指向 class 的成员函数的指针的大小来确定这一点微软 Visual C++。它不适用于其他编译器,尤其是那些实现了 Itanium C++ ABI.

的编译器

在 Microsoft 实施中,class 的布局可能会因虚拟基地 class 的位置而异,而 pointer-to-member-function 将需要应用偏移量才能获得调用的正确 this 指针。当存在虚拟基 class 时,这会导致 pointer-to-member-function 比没有虚拟基时更大。由于 sizeof 运算符是一个编译时常量,因此可以在不同的地方(包括模板参数)使用它来根据是否存在虚拟基来区分代码。

这是一个简单的测试程序(在 Godbolt 上)。如果编译成功,您可以使用成员函数指针的大小来确定是否为 class.

指定了虚拟基 class
struct B {
    void f();
};

struct C: virtual public B {
    void g();
};

int test(int s) {
    switch (s) {
        case sizeof(&C::g):
            return 1;
        case sizeof(&B::f):
            return 2;
    }
    return 0;
}

要确定是否可以使用 std::memcpy,您实际上需要 std::is_trivially_meowable

例如,如果您想使用std::memcpy进行复制,您可以使用std::is_trivially_copyable进行检查。

您还可以检查平凡可构造和平凡可破坏。


正如您在评论中所说,您还想用非平凡的 classes 来做到这一点。这不可避免地会导致未定义的行为,所以我不会尝试。我建议删除那些 classes 中的 vtable 并在依赖未定义行为之前使它们变得微不足道。

此外,如果您使用指向那些 class 的指针,则指针本身是微不足道的。所以你可以用这种方式简单地复制你的class。