【问题标题】:Is there something like is_empty_but_has_virtual_functions?有没有类似 is_empty_but_has_virtual_functions 的东西?
【发布时间】:2020-03-11 14:23:03
【问题描述】:

我想制作一个“接口”/mix-in 类(模板),并确保没有人认为向这个类模板添加成员是个好主意,在这种情况下我想static_assert。 不幸的是,std::is_empty 不允许使用虚函数(因为多态类需要一些空间来存储它们的虚函数表指针或等效的实现细节)。

是否有std::is_empty 的变体允许虚函数,但不允许数据成员(或者容易编写)?

我希望它能够工作(加上我现在想不出的所有黑暗角落案例):

#include <type_traits>

struct A {};
struct B : A {};
struct AA { virtual ~AA() = default; };
struct BB : AA {};

static_assert(std::is_empty_v<A>);
static_assert(std::is_empty_v<B>);

// These should also work with the replacement for is_empty:
static_assert(std::is_empty_v<AA>);
static_assert(std::is_empty_v<BB>);

int main()
{}

Live demo here.

我猜它需要编译器魔法或非常特定于平台的黑客/检查,具体取决于虚拟函数的实现方式。

【问题讨论】:

  • 您能解释一下std::is_empty&lt;type&gt;::value &amp;&amp; std::is_polymorphic&lt;type&gt;::value 无法满足您的需求吗?
  • @Peter 一个具有虚拟方法的类有is_empty&lt;T&gt;::value == false
  • 如果您在团队中并且需要强制执行编码策略,那么可能是时候研究一下 linter:github.com/exercism/cpp/issues/8
  • 您可以尝试利用空基类优化:从中派生一个具有一个数据成员的类,并检查派生类的大小是该数据成员的大小.
  • @user253751 这不起作用,因为虚函数表指针或其他实现定义的细节会以与实现相关的方式增加多态类的大小。

标签: c++ c++17 typetraits is-empty empty-class


【解决方案1】:

我会这样做:

struct dummy_polymorphic
{
    virtual ~dummy_polymorphic() {}
};

template <typename T>
inline constexpr bool empty_maybe_polymorphic_v = std::is_empty_v<T> ||
    (std::is_polymorphic_v<T> && sizeof(T) <= sizeof(dummy_polymorphic));

这是我能想到的最好的方法,但它有一些局限性:

  • 我们假设多态类的开销始终相同(通常是一个非常安全的假设,除非您的类由于多重继承而最终具有多个 vtable 指针)。我看不出有什么办法摆脱 这个限制。

  • 如果T 有重复的空碱基,它会中断:

    struct A {};
    struct B : A{};
    struct C : A, B {virtual ~C() {}};
    
    std::cout << sizeof(C) << '\n'; // 16, rather than 8
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-08
    相关资源
    最近更新 更多