带NSDMI的C++内部结构体默认可构造性表现异常是什么原因?
该问题的核心是GCC与Clang当前的实现缺陷
底层原因
对于带有默认成员初始化器的嵌套类,编译器本应在嵌套类自身定义完成时,就确定其隐式默认构造函数的可用性。但目前GCC和Clang的实现中,错误地将这一判定流程推迟到了外围类完全定义完成之后。
同时std::is_default_constructible这类类型特征的查询结果会被编译器缓存,一次错误的判定结果会被后续所有查询复用。
各现象的对应解释
- 无内部static_assert时外部断言可通过:外部的静态断言是在外围类
outer完全定义完成后才处理的,此时编译器已经完成了inner类隐式默认构造函数的判定,能正确识别inner支持默认构造,因此断言通过。 - 打开内部static_assert后两个断言都失败:类作用域内的静态断言会在解析到对应位置时立即执行,此时外围类
outer还未定义完成,编译器尚未完成inner的隐式构造函数判定,错误返回false。该错误结果被缓存后,后续外部的断言也会复用该结果,导致两个断言全部失败。 - static_assert放在成员函数内可通过:成员函数的函数体属于类的迟后解析内容,会等整个外围类定义完成后再处理,此时
inner的构造函数判定已经完成,能得到正确结果。 - 移除
x的默认初始化器后断言可通过:没有默认成员初始化器时,inner的隐式默认构造是平凡构造,编译器不需要推迟判定流程,在inner定义完成时就能直接确定它支持默认构造。 - 添加显式默认构造函数后断言可通过:显式声明的构造函数不需要编译器隐式生成,解析到构造函数声明时就能直接确定它存在,不需要等待后续的隐式生成判定流程。
内容的提问来源于stack exchange,提问作者einpoklum
相关产品推荐
相关产品推荐

