如何解决在访问常量表达式中的工会成员时出错
遇到问题时,我正在用工会做一些实验。
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
的元素)都会重现该错误。似乎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 >> 24)}
{ }
constexpr U(uint32_t x,const init_byte_t&,const rinit_t&) noexcept :
byte{uint8_t(x >> 24),uint8_t(x)}
{ }
如果有人可以为此提供更好的解决方案,那就太好了。
解决方法
您的constexpr
函数在c ++ 20之前无效,因为它违反了以下rule:
表达式e是核心常量表达式,除非按照抽象机的规则对e求值将对以下表达式之一求值:
一个赋值表达式或一个赋值运算符([class.copy])的调用将改变联合的活动成员;
从c ++ 20开始,此限制已得到澄清here:
表达式e是核心常量表达式,除非按照抽象机的规则对e求值将对以下表达式之一求值:
为其活动成员(如果有)可变的联合调用隐式定义的复制/移动构造函数或复制/移动赋值运算符,除非联合对象的生存期始于E的评估;
我相信这会使您的代码有效。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。