我该如何访问位域成员?

3

我理解你不能有指向位字段的指针,因为指针只能区分字节级别的地址,而不能区分位级别的地址。对位字段的引用也是不允许的。是否还有其他方法能够间接地引用位字段的成员?理想情况下,我希望能够使用类似于下面的mys1array行的数组语法来访问它们。我知道引用数组是不合法的,但也许有人在这方面有一些智慧的知识,能够实现类似的目标。

typedef struct{
    unsigned short a : 5;
    unsigned short b : 3;
    unsigned short c : 8;
}myStruct;

class myClass{
public:
    myStruct s1;
    //unsigned short &mys1array[] = {&s1.a, &s1.b ,&s1.c};
};

std::function<unsigned int()> getters[] = {[&](){ return s1.a; }, [&](){ return s1.b; }, [&](){ return s1.c; }}… (对于setters也类似) - Jarod42
@Jarod42,我似乎无法使用它打印出正确的值。你能否向我解释一下这是怎么错了?请注意,我当然已经初始化了s1成员的值。 printf(“%s”,getters [0]); 它一直打印出类似“6299904”的东西。 - StephBoyardee
在这里按预期工作:http://coliru.stacked-crooked.com/a/c52356c4c2342a71。请注意,IlCapitano使用了与我的评论相同的解决方案。 - Jarod42
2个回答

3

您可以使用初始化为lambda表达式的函数指针数组,通过不同的函数来访问位域中的每个元素。

class myClass {
public:
    myStruct s1;
    static constexpr unsigned short (*accessors)(myStruct const &s)[] = {
        +[](myStruct const &s) -> unsigned short { return s.a; }
        // ...
    };
};

你需要将myStruct的一个实例传递给函数。另一种方法是使用std::function和捕获lambda表达式:

class myClass {
public:
    myStruct s1;
    std::function<unsigned short()> accessors[3];

    myClass(myStruct s)
        : s1(s),
          accessors{
              [this]() -> unsigned short { return this->s1.a; },
              // ...
          }
    {}

    // ...
};

不要忘记,使用这个时,你需要实现复制构造函数、移动构造函数和赋值运算符,因为 lambda 捕获了 this


1
你只能通过类来访问位字段。如果你想要间接访问,可以使用指向封装类对象的指针或引用。
如果你想要遍历类中的位字段,可以编写自定义迭代器,但是实现这样的迭代器可能需要一些显式硬编码,因为C++缺乏反射功能来自动化它。以下是一个不完整的概念证明:
struct myStruct {
    unsigned short a : 5;
    unsigned short b : 3;
    unsigned short c : 8;

    struct reference {
        myStruct* parent;
        unsigned char field;
        
        operator unsigned short() {
            switch(field) {
                case 0: return parent->a;
                case 1: return parent->b;
                case 2: return parent->c;
                default: assert(false);
            }
        }
        
        reference& operator=(unsigned short u) {
            switch(field) {
                case 0: parent->a = u; return *this;
                case 1: parent->b = u; return *this;
                case 2: parent->c = u; return *this;
                default: assert(false);
            }
        }
        
        void operator++() {
            ++field;
        }
        
        friend auto operator<=>(const reference&, const reference&) = default;
    };
    
    struct iterator
    {
        //TODO add missing member definitions, const overloads etc.
        
        reference current;
        reference operator*() {
            return current;
        }
        void operator++() {
            ++current;
        }
        
        friend auto operator<=>(const myStructIterator&, const myStructIterator&) = default;
    };
    
    iterator begin() {
        return {this, 0};
    }
    
    iterator end() {
        return {this, 3};
    }
};

int main()
{
    myStruct s {};
    for(int i=3; auto f : s) {
        f = i++;
    }
    for(auto f : s) {
        std::cout << f << '\n';
    }
}
< p > reference 类足以表示位域的间接引用,而 iterator 允许将字段视为可迭代范围。 < /p >

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接