提问人:Jan Schultke 提问时间:9/23/2023 最后编辑:timrauJan Schultke 更新时间:10/1/2023 访问量:160
作者对 optional<bool> 的基于联合的实现是否在 P2641 中定义得当?
Is the author's union-based implementation of an optional<bool> well-defined in P2641?
问:
在 P2641r4: Checking 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; } };
但是,我不相信。也就是说,看起来并不安全,因为如果 a 是活跃的工会成员,那么就会访问一个不活跃的成员并执行工会类型的双关语。据我所知,这在 C++ 中是不允许的。has_value()
bool
c != 2
作者解释说,由于正在读取非活动的联合成员,因此无法执行此操作,并提供了以下实现:
constexpr auto has_value() const -> bool { if consteval { return std::is_within_lifetime(&b); } else { return c != 2; } }
作者这是什么意思?这是否意味着您不能在常量表达式中读取非活动的联合成员,但否则是允许的? 此代码的格式是否完全正确,或者它是否依赖于允许在运行时使用联合类型双关语的编译器扩展?
注意:这是作者对 P2641 中明确定义的可选<bool>的实现的姊妹问题,该问题讨论了其他实现。
答:
我假设它像往常一样有一个先决条件,即已使用重载。当可选为空时使用显然是UB,但也不是预期用途。operator*
OptBool(bool b)
operator*
When 是活动成员,则访问 具有未定义的行为,因为它必须超出生命周期。b
c
这里的目的是查看对象表示,这可以通过添加看似不必要的强制转换来实现:
return *reinterpret_cast<unsigned char*>(reinterpret_cast<OptBool*>(&c)) != 2;
内部转换将生成指向对象的指针,因为该指针是标准布局,并且指针可与子对象互换。OptBool
OptBool
c
然后,外部强制转换将生成指向具有表达式类型 的对象的指针。通过它进行访问不是别名冲突。但是,目前尚未指定此访问应读取的值。目的是让它读取对象(以及 or 对象)的对象表示的第一个字节,但目前没有指定要发生这种情况。有 P1839 试图解决这个问题。在实践中,这是每个人都认为的行为,即使标准目前没有这么说,这也是一个缺陷。OptBool
unsigned char*
OptBool
bool
char
无论如何,实现当然假定了 的特定实现,特别是它的大小、对齐方式和对象/值表示。bool
标准中没有任何内容要求或不存储为值 2。
要求为 0 并且要求为 1,但这些是强制转换的结果,而不是存储在内存中的值。
查看 https://stackoverflow.com/a/19351548/362589false
true
int(false)
int(true)
评论
bool
optional<T>
bool
boost::tribool
optional<bool>