std::is_default_constructible对嵌套类返错是GCC bug还是用户错误?
问题说明
MyClass::MyData 从语法上看完全满足默认构造要求,但 std::is_default_constructible_v<MyClass::MyData> 却返回false,复现代码如下:
#include <variant> #include <type_traits> class MyClass { public: struct MyData { // 此处是否声明默认构造函数不会影响结果 MyData() = default; // 修复方案:不使用"= default",而是显式定义空构造函数即可正常工作 // (但完全移除构造函数无法解决该问题) //MyData() { } const char* m_name{ nullptr }; }; std::variant<MyData> m_var; // 改用如下初始化语句可修复该问题 //std::variant<MyData> m_var{ MyData{} }; // 或者注释掉下方的构造函数也可修复问题 MyClass() { } }; // 注意此处存在不一致:显然可以默认构造MyData类型的x对象,但static_assert却判定失败 MyClass::MyData x; static_assert(std::is_default_constructible_v<MyClass::MyData>); MyClass y; static_assert(std::is_default_constructible_v<MyClass>); int main() { return 0; }
原因分析
原帖作者注:该问题属于已收录的重复问题,对应问题的解答可以完全解释该现象,仅本案例的触发场景稍有区别。
触发该问题的核心逻辑如下:
- 编译器首次实例化检查
std::is_default_constructible类型特征的时机,是类内声明std::variant<MyData> m_var成员的阶段 - 此时外围类
MyClass还未完成完整声明,GCC在这个不完整的上下文环境中判定MyData不满足默认构造要求,因此std::is_default_constructible_v返回false - 等执行到全局作用域的
static_assert检查时,整个类的声明已经完成,MyData实际上是可以正常默认构造的,但C++标准要求类型特征的查询结果在整个翻译单元内必须保持恒定,因此该特征值仍然返回之前缓存的false结果
目前还没有最终结论判定这到底是GCC的bug(错误拒绝了符合标准的合法代码),还是MSVC编译器的bug(错误放行不符合标准的非法代码),但该问题的核心触发逻辑和已记录的同类问题完全一致。
内容的提问来源于stack exchange,提问作者Rob L
相关产品推荐
相关产品推荐

