在 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; } };
但是,我并不相信。即has_value()
看起来并不安全,因为如果 bool
是活跃的 union 成员,则 c != 2
访问非事件成员并执行 union 类型双关。据我所知,这在 C++ 中是不允许的。
作者解释说这是无法完成的,因为正在读取不活动的 union 成员,并提供了以下实现:
constexpr auto has_value() const -> bool { if consteval { return std::is_within_lifetime(&b); } else { return c != 2; } }
作者这句话的意思是什么?这是否意味着您无法读取常量表达式中的非事件 union 成员,但否则会被允许? 该代码是否完全格式良好,或者是否依赖于允许在运行时进行 union 类型双关的编译器扩展?
注意:这是 Is the author's implementation of an optional<bool> well-defined in P2641? 的姐妹问题其中讨论了其他实现。
最佳答案
我假设 operator*
像往常一样有一个先决条件,即已使用 OptBool(bool b)
重载。当可选值为空时使用 operator*
显然是 UB,但也不是预期用途。
当 b
是事件成员时,访问 c
具有未定义的行为,因为它必须超出生命周期。
这里的目的是查看对象表示,这可以通过添加看似不必要的强制转换来实现:
return *reinterpret_cast<unsigned char*>(reinterpret_cast<OptBool*>(&c)) != 2;
内部转换将产生一个指向 OptBool
对象的指针,因为 OptBool
是标准布局,并且可以与 c
子对象进行指针互换.
然后,外部转换将生成一个指向具有表达式类型 unsigned char*
的 OptBool
对象的指针。通过它进行访问并不违反别名。但是,目前尚未指定此访问应读取什么值。其目的是读取 OptBool 对象(以及 bool 或 char 对象)的对象表示形式的第一个字节,但是目前还没有指定会发生这种情况。有P1839试图解决这个问题。实际上,这是每个人都认为的行为,即使目前标准没有这么说,这是一个缺陷。
无论如何,实现当然假设了 bool
的特定实现,特别是它的大小、对齐方式和对象/值表示。
关于c++ - 作者基于 union 的可选 <bool> 实现在 P2641 中定义良好吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77162785/