作者基于联合的可选<bool>实现在 P2641 中定义良好吗?

问题描述 投票:0回答:1

P2641r4:检查联合替代方案是否处于活动状态中,作者提供了

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
是活动联合成员,那么
c != 2
会访问非活动成员并执行联合类型双关。据我所知,这在 C++ 中是不允许的。

作者解释说这是无法完成的,因为正在读取一个不活跃的联合成员,并提供了以下实现:

  constexpr auto has_value() const -> bool {
    if consteval {
      return std::is_within_lifetime(&b);
    } else {
      return c != 2;
    }
  }

作者这句话的意思是什么?这是否意味着您无法读取常量表达式中的非活动联合成员,但否则会被允许? 该代码是否完全格式良好,或者是否依赖于允许在运行时进行联合类型双关的编译器扩展?


注意:这是作者对可选的实现是否在 P2641 中明确定义的姐妹问题?讨论了其他实现。

c++ language-lawyer union type-punning c++26
1个回答
0
投票

我假设

operator*
像往常一样有一个先决条件,即已使用
OptBool(bool b)
重载。当可选值为空时使用
operator*
显然是 UB,但也不是预期用途。

b
是活动成员时,访问
c
具有未定义的行为,因为它必须超出生命周期。

这里的目的是查看对象表示,这可以通过添加看似不必要的强制转换来实现:

return *reinterpret_cast<unsigned char*>(reinterpret_cast<OptBool*>(&c)) != 2;

内部转换将产生一个指向

OptBool
对象的指针,因为
OptBool
是标准布局并且可以与
c
子对象进行指针相互转换。

然后,外部转换将生成一个指向表达式类型为

OptBool

unsigned char*
 对象的指针。通过它进行访问并不违反别名。但是,目前尚未指定此访问应读取什么值。其目的是读取 
OptBool
 对象(以及 
bool
char
 对象)的对象表示的第一个字节,但目前尚未指定会发生这种情况。有 
P1839 试图解决这个问题。实际上,每个人都认为这是一种行为,即使标准目前没有这么说,这是一个缺陷。

在任何情况下,当然的实现都假设

bool

的具体实现,特别是它的大小、对齐方式和对象/值表示。

© www.soinside.com 2019 - 2024. All rights reserved.