利用C++标准布局联合与共同初始序列实现带检查位字段是否合规?
C++标准布局联合中自定义成员函数是否违反class.mem/28条款?
问题背景
C++标准条款class.mem/28规定:标准布局联合中,若活跃成员为结构体类型T1,可读取另一结构体成员T2的非静态数据成员m(m属于T1与T2的共同初始序列),行为等同于引用T1的对应成员。
为实现带额外检查的位字段功能,我尝试创建包含多个结构体的标准布局联合,每个结构体都包含uint64_t成员:
CustomField模板结构体实现
template<some params> struct CustomField { void operator=(uint64_t newVal) { val = someCustomInsertFn(newVal); } operator uint64_t() const { return someCustomExtractFn(val); } uint64_t val; // 注意:该成员在联合中与其他所有字段及下方的`all`共用存储 };
联合定义
union CheckedBitField { struct { uint64_t all; }; CustomField<some param> fieldOne; CustomField<some other param> fieldTwo; };
这些CustomField结构体通过自定义赋值运算符和转换运算符,实现了基础位字段不具备的额外检查(如值有效性、截断检查),示例用法:
CheckedBitField b{}; b.fieldOne = 5; // 此处会执行自定义检查逻辑
疑问
为CustomField添加这些额外成员函数是否违反class.mem/28条款的规则?
回答
不违反class.mem/28条款的规则,原因如下:
- 条款核心约束是数据布局而非成员函数:class.mem/28的规则聚焦于标准布局类型的共同初始序列、联合成员的存储共用逻辑,仅对类型的数据成员布局有要求,成员函数不属于对象的存储部分,不会影响类型的布局属性。
- CustomField仍属于标准布局类型:
CustomField没有虚函数、非标准布局基类或不符合要求的数据成员,自定义成员函数不会改变其标准布局属性——标准布局的判定只看数据成员的结构和继承关系,与成员函数无关。 - 共同初始序列要求仍满足:联合中所有成员的共同初始序列都包含
uint64_t类型的首成员(匿名结构体的all、每个CustomField的val),完全符合条款对共同初始序列的定义。 - 自定义函数未破坏联合存储规则:赋值和转换运算符只是对
val的读写做了封装,本质上依然是对联合共用存储区的合法访问,没有违反联合成员活跃性相关的规则,读取非活跃成员的共同初始序列成员时,行为仍符合条款规定。
内容的提问来源于stack exchange,提问作者Mike Vine
相关产品推荐
相关产品推荐

