为何我的类无法默认构造?附代码复现与异常现象
奇怪的编译差异?来拆解这个Clang 9的bug
先把你的代码贴出来方便大家看:
#include <type_traits> template <typename T> class A { public: static_assert(std::is_default_constructible_v<T>); }; struct B { struct C { int i = 0; }; A<C> a_m; // 这里编译失败,静态断言触发 }; int main() { A<B::C> a; // 这里却能正常编译? }
你遇到的现象完全合理,这其实是Clang 9.0.0的一个已知bug,和编译器处理嵌套类的类型完整性时机有关。
为什么会出现这种差异?
问题出在编译器对嵌套类的默认构造能力判断时机上:
- 当编译器处理
B内部的A<C> a_m时,虽然C的定义写在前面,但此时C对编译器来说还不是“完全完整”的类型——它没法正确识别到:因为默认成员初始化器int i=0的存在,C会被隐式生成默认构造函数,所以std::is_default_constructible_v<C>错误返回了false,触发了静态断言。 - 而到了
main函数里,B::C已经是完全定义的类型,编译器能正确判断它是默认可构造的,所以静态断言顺利通过。
当你去掉C的默认成员初始化器后,C变成了简单的聚合类,编译器在处理B内的a_m时,能直接识别它可以被默认初始化,所以静态断言不会触发。
怎么解决?
有两个简单的处理方式:
- 升级Clang版本:这个bug在Clang 10及以后的版本已经被修复,升级后代码就能正常编译,不需要修改任何代码。
- 给C显式添加默认构造函数:如果暂时没法升级编译器,给
C手动声明默认构造函数,让编译器在处理B内的a_m时能明确知道它是默认可构造的:
struct B { struct C { int i = 0; C() = default; // 显式声明默认构造 }; A<C> a_m; // 现在编译正常了 };
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

