我在尝试使用联合体进行一些实验时遇到了问题。
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};
我在 g++ 的版本 5.1 和 8.1 中使用 -std=c++14
、-std=c++17
和 -std=c++2a
时遇到了这个错误:
accessing 'U::byte' member instead of initialized 'U::dword' member in constant expression
访问和赋值成员byte
的元素,无论是来自temp
还是this
,都会产生错误。似乎编译器将byte
识别为“未初始化”的成员,即使byte
和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)}
{ }
如果有人能提供更好的解决方案,那就太棒了。
-std=c++20
来接受您的替代第二个构造函数。尽管如此,我不确定这是否符合标准。 - chi