可选类、嵌套类与is_constructible的异常交互问题问询
这是编译器历史实现bug,而非C++标准漏洞
标准对InnerType的定义解析
你的OptionalsStruct::InnerType没有显式声明构造函数,但给成员b提供了默认成员初始化器(bool b{})。根据C++17标准,编译器会为它生成隐式默认构造函数,这个构造函数满足:
- 属于
constexpr(C++17起) - 是
noexcept的(因为成员的默认初始化不会抛出异常) - 完全符合
std::default_constructible、std::constructible、std::nothrow_default_constructible的概念要求
各编译器表现的原因分析
不同版本编译器的异常表现都是历史实现bug,而非标准本身的问题:
- Clang 9、10:错误判定
InnerType不是nothrow可构造,源于当时对嵌套类型结合默认成员初始化器的隐式构造函数特性推导逻辑存在缺陷; - GCC 10:割裂了nothrow属性与可构造性的关联,错误认为
InnerType不可构造/默认构造,但具备nothrow属性,属于概念判定逻辑错误; - Clang 8:特殊表现是早期版本对C++17默认成员初始化器与隐式构造函数交互逻辑的实现不完善导致的;
- Clang 11+:已经修复了这些bug,后续版本的判定行为符合C++17标准要求。
验证方法
可以通过以下static_assert代码验证编译器是否符合标准:
#include <type_traits> #include <optional> struct OptionalsStruct { struct InnerType { bool b{}; }; OptionalsStruct() = default; std::optional<InnerType> oInnerType; }; static_assert(std::is_default_constructible_v<OptionalsStruct::InnerType>); static_assert(std::is_nothrow_default_constructible_v<OptionalsStruct::InnerType>); static_assert(std::is_constructible_v<OptionalsStruct::InnerType>);
符合标准的编译器会通过所有断言,旧版本存在bug的编译器会触发断言失败。
内容的提问来源于stack exchange,提问作者Paolo M
相关产品推荐
相关产品推荐

