具有公共初始序列的标准布局联合来创建检查位字段作为位字段的替代品?

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

给定class.mem/28:

https://eel.is/c++draft/class.mem#general-28

其中规定:

在具有结构类型 T1 的活动成员的标准布局联合中,它 允许读取另一个联合体的非静态数据成员 m 结构类型 T2 的成员,前提是 m 是公共首字母的一部分 T1和T2的顺序;行为就像相应的成员 T1 获得提名。

我认为创建一个具有多个(不同)结构的联合是有效的,每个结构都有一个

uint64_t
成员:

template<some params>
struct CustomField
{
    void operator=(uint64_t newVal)
    {
        val = someCustomInsertFn(newVal);
    }

    operator uint64_t() const
    {
        return someCustomExtractFn(val);
    }

    uint64_t val; // Note that this is used in a union and so aliases with all other fields and the `all` below
};

然后:

union CheckedBitField
{
    struct { uint64_t all; }
    CustomField<some param> fieldOne;
    CustomField<some other param> fieldTwo;
};

这个想法是一个带有结构成员的简单联合,每个结构成员只有一个

uint64_t val

但是这些自定义字段具有自定义

void operator=(uint64_t newVal)
operator uint64_t() const
运算符,可以对基本位字段所能获得的内容添加额外的检查。

插入函数的一个示例是添加额外的检查,以确保您正在写入的值在逻辑上有效和/或不会被截断。

所以这个代码是有效的 - 就像在普通的位字段中一样:

CheckedBitField b{};
b.fieldOne = 5; // This runs custom code.

添加这些附加函数是否会违反 class.mem/28 规则和/或者我遗漏了什么?

完整的可运行代码 - 添加了设置字段的最小/最大值的功能: https://godbolt.org/z/ozz16GEP8

c++ language-lawyer union bit-fields
1个回答
0
投票
在您的报价中的任何内容变得相关之前,

b.fieldOne = 5;
已经具有未定义的行为。

fieldOne
成员不是活动的,因此相应的成员子对象不在其生命周期内,因此在其上调用非静态成员函数是UB。

分配也不会启动生命周期并使成员处于活动状态,因为在这种情况下,

=
既不是内置运算符,也不是普通的赋值运算符。 (这是唯一的例外,不需要
new
或隐式创建对象的函数来更改联合的活动成员。)

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