std::is_empty 在类类型不含非静态数据成员、无虚函数且所有基类也满足该条件时返回 true;它忽略构造/析构函数、成员函数及 static 成员,但受虚函数、非静态成员、继承非空基类等影响而返回 false。

std::is_empty 在什么情况下返回 true
std::is_empty 判断的是类类型是否「不含非静态数据成员」且「不含虚函数」,同时其基类也满足该条件。它不关心构造函数、析构函数、成员函数是否存在,也不看是否有 static 成员——这些都不影响空类判定。
常见误判场景:加了虚函数、定义了 virtual ~Base() = default;、继承自带成员的基类、甚至只加了一个 int 都会让 std::is_empty 返回 false。
- 空类典型例子:
struct Empty {};→std::is_empty_v<empty></empty>为true - 有虚函数:
struct HasVTable { virtual void f(); };→false(vtable 指针隐式存在) - 含 static 成员:
struct WithStatic { static int x; };→true(static 不占实例大小) - 含默认成员初始化器:
struct BadInit { int x{}; };→false(x 是非静态成员)
std::is_empty 和 EBO(空基类优化)的关系
std::is_empty 是 EBO 可生效的前提,但不是充分条件。编译器只对 std::is_empty_v<base> 为 true 的基类才可能应用 EBO;但即使满足,也不保证一定优化——取决于具体布局规则和 ABI。
真正能观察到 EBO 效果的方式是看派生类大小:sizeof 是否等于最宽非空基类/成员的大小。如果空基类被“压扁”进对象布局中,就不会额外增加 sizeof。
立即学习“C++免费学习笔记(深入)”;
- 典型 EBO 成功:
struct Base {}; struct Derived : Base { int x; };→sizeof(Derived) == sizeof(int) - EBO 失败(即使 Base 是空的):
struct Base {}; struct Derived : Base, Base {};→ 二义性,无法继承两次同名空基类 - 注意多重继承顺序:
struct D : A, B中若A和B都为空,通常只有第一个可能被 EBO,第二个仍需唯一地址
用 std::is_empty 做 SFINAE 或 constexpr 分支的坑
直接在模板约束里用 std::is_empty_v<t></t> 很自然,但要注意:它对非类类型(如 int、void)是 false,而对未定义的类(前向声明)是 SFINAE-unfriendly 的——会导致硬错误而非约束失败。
- 安全写法(配合
std::is_class_v):requires std::is_class_v<t> && std::is_empty_v<t></t></t> - 避免裸用:
std::is_empty_v<t></t>在T是class X;前向声明时触发编译错误 - constexpr if 中没问题,但记得先
if constexpr (std::is_class_v<t>)</t>再判断 empty,否则可能 instantiate 不完整类型 - 别把它当
std::is_trivially_copyable用——空类可以是非 trivial 的(比如有非 trivial 析构函数)
std::is_empty 不能替代 sizeof(T) == 1 的判断
有人用 sizeof(T) == 1 猜测空类,这是危险的。某些空类因对齐要求(如 alignas(16) struct A {};)会变成 sizeof(A) == 16,但仍是 std::is_empty_v<a></a> 为 true;反过来,含 char 成员的类 sizeof 也是 1,却不是空类。
-
alignas(8) struct Empty {};→sizeof == 8,但std::is_empty_v仍为true -
struct NotEmpty { char c; };→sizeof == 1,但std::is_empty_v是false - 所以运行时或调试中靠
sizeof推断空类,大概率踩坑
真正要识别 EBO 友好类型,还是得信 std::is_empty,而不是看大小。它的语义明确,且由标准保证;而 sizeof 受对齐、ABI、编译器实现细节影响太大。










