1

我在C++17中有以下代码,我在其中定义了struct一个位掩码,并且具有类型为位字段的成员变量bool

我正在定义一个tie函数,以便我可以将它转换为一个可比较的std::tuple对象,这很方便。问题是:std::tie似乎做错了什么,并且第一个成员变量的值似乎是false即使默认构造函数已正确将其初始化为true.

手动对位字段进行单个引用bool似乎可以按预期工作。

我目前正在使用 CLang 12。

这是代码:

#include <cassert>
#include <tuple>

struct Bitmask
{
    Bitmask( )
        : first{true}
        , second{false}
        , third{false}
    {
    }

    bool first : 1;
    bool second : 1;
    bool third : 1;
};

auto
tie( const Bitmask& self )
{
    return std::tie( self.first, self.second, self.third );
}

int main()
{
    Bitmask default_bitmask; 
    Bitmask custom_bitmask;
    custom_bitmask.first = false;
    custom_bitmask.second = true;

    const bool& ref_1 = default_bitmask.first;
    const bool& ref_2 = custom_bitmask.first;

    assert( ref_1 != ref_2 ); // this check works   

    assert( std::get< 0 >( tie( default_bitmask ) ) == true ); // this check fails
    assert( std::get< 0 >( tie( custom_bitmask ) ) == false ); // this check works
}
4

1 回答 1

2

不可能有一个位域的引用或指针。从cppreference

因为位域不一定从字节的开头开始,所以不能取位域的地址。对位域的指针和非常量引用是不可能的。从位域初始化 const 引用时,会创建一个临时对象(其类型是位域的类型),使用位域的值初始化副本,并将引用绑定到该临时对象。

并从标准

address-of 运算符&不应应用于位域,因此没有指向位域的指针。非常量引用不应绑定到位字段 ( dcl.init.ref )。

以及随附的说明

[注3:如果类型引用的初始化器是一个引用const T&位域的左值,则该引用绑定到一个临时初始化以保存位域的值;引用不直接绑定到位域。请参阅dcl.init.ref。——尾注]

编译的唯一原因是因为tieBitmask类型作为const. 它的每个位域成员都被视为 const 并std::tie返回一个std::tupleconst 引用。正如上面引用的段落所说,这些引用指的是数据成员的副本,而不是那些实际的数据成员。然后,就像你试图const int & x = 10;通过引用返回 a 一样,你最终会得到一个悬空引用的元组。最后,试图获取引用对象的值会导致未定义的行为。

于 2021-05-07T15:10:15.733 回答