P2641中基于union的optional<bool>实现及改进版是否合规?
关于P2641r4中
optional<bool>实现的标准合规性疑问 问题背景
在C++提案《P2641r4: Checking if a union alternative is active》中,作者给出了一个optional<bool>的实现示例,并声称符合标准:
struct OptBool { union { bool b; char c; }; OptBool() : c(2) { } OptBool(bool b) : b(b) { } auto has_value() const -> bool { return c != 2; } auto operator*() -> bool& { return b; } };
但存在疑问:当bool是union的活跃成员时,has_value()中访问非活跃成员c属于union类型双关,这在C++标准中是不被允许的。
作者随后给出改进实现:
constexpr auto has_value() const -> bool { if consteval { return std::is_within_lifetime(&b); } else { return c != 2; } }
需要明确两个问题:
- 作者的意图是不是常量表达式中不能读取union非活跃成员,但运行时允许?
- 改进后的代码是否完全符合标准,还是依赖编译器扩展?
解答
1. 作者的核心意图
是的,作者的思路就是针对常量表达式和运行时两种场景做差异化处理:
- 常量表达式语境:C++标准对常量表达式的约束非常严格,访问union的非活跃成员属于未定义行为,因此必须用
std::is_within_lifetime(&b)(P2641提案引入的新工具,用于检测union成员是否处于活跃状态)来合法判断。 - 运行时语境:作者默认了主流编译器在运行时对union类型双关的宽松处理——虽然C++标准本身不允许跨活跃成员的访问,但GCC、Clang、MSVC等主流编译器都提供了相关扩展支持,实际运行中不会出现问题。
2. 改进后代码的标准合规性
改进后的代码并非完全符合标准:
- 常量表达式分支(
if consteval块)是合规的:std::is_within_lifetime正是P2641提案要引入的标准工具,用于合法检测union成员的活跃状态,这部分完全符合提案通过后的标准要求。 - 运行时分支(
else块)依然依赖编译器扩展:C++标准始终禁止访问union的非活跃成员,哪怕是在运行时。作者这里是利用了主流编译器的实际行为——它们通常允许这种类型双关操作,前提是成员的内存布局兼容(bool和char的大小通常相同,内存布局一致)。
简言之,改进版在常量表达式场景下符合标准,运行时场景则依赖编译器的非标准扩展。
内容的提问来源于stack exchange,提问作者Jan Schultke
相关产品推荐
相关产品推荐

