c++ - 在常量表达式中访问 union 成员时出错

标签 c++ constexpr unions

当我遇到问题时,我正在用 union 做一些实验。

union U
{
  // struct flag for reverse-initialization of each byte
  struct rinit_t { };
  constexpr static const rinit_t rinit{};

  uint32_t dword;
  uint8_t byte[4];

  constexpr U() noexcept : dword{} { }

  constexpr U(uint32_t x) noexcept : dword{x} { }

  constexpr U(uint32_t x, const rinit_t&) noexcept : dword{}
  {
    U temp{x};
    byte[0] = temp.byte[3];
    byte[1] = temp.byte[2];
    byte[2] = temp.byte[1];
    byte[3] = temp.byte[0];
  }
};
这是我的示例实例:
constexpr U x{0x12345678, U::rinit};
我在带有 -std=c++14-std=c++17-std=c++2a 的 g++ 5.1 和 8.1 版本中遇到此错误:
accessing 'U::byte' member instead of initialized 'U::dword' member in constant expression
访问和分配成员 byte 的元素,无论是来自 temp 还是 this ,都会重现错误。即使 bytebyte 共享相同的地址,似乎 dword 也被编译器识别为“未初始化”成员。
我曾经修改过第二个构造函数:
constexpr U(uint32_t x) noexcept :
  byte{uint8_t(x), uint8_t(x >> 8), uint8_t(x >> 16), uint8_t(x >> 24)}
{ }
但是我在最终产生似乎是编译器错误后恢复了:
main.cpp:73:37: internal compiler error: in complete_ctor_at_level_p, at expr.c:5844
   constexpr U x{0x12345678, U::rinit};
                                     ^

Please submit a full bug report,
with preprocessed source if appropriate.
See <http://tdm-gcc.tdragon.net/bugs> for instructions.
对于我当前的修复,我添加了一个转换器:
// converts the value of a uint32_t to big endian format
constexpr static uint32_t uint32_to_be(uint32_t x)
{
  return ( (x >> 24) & 0xFF)       |
         ( (x << 8)  & 0xFF0000)   |
         ( (x >> 8)  & 0xFF00)     |
         ( (x << 24) & 0xFF000000);
}
我修改了第三个构造函数:
constexpr U(uint32_t x, const rinit_t&) noexcept : dword{uint32_to_be(x)} { }
我只是好奇为什么我会收到错误。谁能帮我理解这个问题?
更新:
根据我最近的测试,在 constexpr union 构造函数中,我不能使用不在初始化列表中的非静态数据成员。因此,我添加了一些 struct 标志来显式指定某个非静态数据成员的初始化。
// struct flag to explicitly specify initialization of U::dword
struct init_dword_t { };
constexpr static const init_dword_t init_dword{};

// struct flag to explicitly specify initialization of U::byte
struct init_byte_t { };
constexpr static const init_byte_t init_byte{};
有了它,我还为这种初始化添加了新的构造函数。这里有些例子:
constexpr U(const init_byte_t&) noexcept : byte{} { }

// for some reason, this version does not reproduce the internal compiler error
constexpr U(uint32_t x, const init_byte_t&) noexcept :
  byte{uint8_t(x), uint8_t(x >> 8), uint8_t(x >> 16), uint8_t(x >> 24)}
{ }

constexpr U(uint32_t x, const init_byte_t&, const rinit_t&) noexcept :
  byte{uint8_t(x >> 24), uint8_t(x >> 16), uint8_t(x >> 8), uint8_t(x)}
{ }
如果有人可以为此提供更好的解决方案,那就太好了。

最佳答案

您的 constexpr函数在c++20之前无效,因为它违反了以下rule :

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

an assignment expression or invocation of an assignment operator ([class.copy]) that would change the active member of a union;



从 c++20 开始,此限制已得到澄清 here :

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

an invocation of an implicitly-defined copy/move constructor or copy/move assignment operator for a union whose active member (if any) is mutable, unless the lifetime of the union object began within the evaluation of E;



我相信这使您的代码有效。

关于c++ - 在常量表达式中访问 union 成员时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63753257/

相关文章:

c++ - g++-7.0/访问硬件中 constexpr 函数的不同行为

c++ - constexpr 函数可能存在错误?

c++ - c++中的 union 它们是否可行

包含结构的 C union - 内存映射 - 编译器跳过一个字节?

具有类成员和 constexpr 链接时优化的 C++11 枚举

c++ - 访问不活动的 union 成员和未定义的行为?

c++ - 无法在动态链接库中找到过程入口点 _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev

c++ - 在我的类(class)中使用 < 的 sort() 问题

c++ - C++为类方法实现超时功能模板

c++ - async_connect 不调用 TCP 客户端类中的处理程序