StephBoyardee
StephBoyardee

Reputation: 33

How else can I access a bit field members?

So I understand that you can't have pointers to bit-fields because the pointers can only distinguish addresses to the byte level, not bit level. References to bit-fields are also not allowed. Are there any other ways that I would be able to reference the members of the bit field indirectly? Ideally I would be able to access them following using array syntax similar to the mys1array line below. I know arrays of references are illegal but perhaps someone has some sage knowledge out there about some other mechanisms which could achieve a similar goal.

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};
};

Upvotes: 3

Views: 1148

Answers (2)

eerorika
eerorika

Reputation: 238411

You can only access bit fields through the class. You can get indirection by having a pointer or reference to the enclosing class object.

You could write a custom iterator if you wanted to iterate the bitfields within the class, but implementation of such iterator may require some explicit hard-coding since C++ lacks reflection capabilities to automate it. Here is an incomplete proof-of-concept:

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';
    }
}

The reference class is sufficient to represent indirection for the bit fields and the iterator allows treating the fields as an iterable range.

Upvotes: 2

IlCapitano
IlCapitano

Reputation: 2094

You could use an array of function pointers that are initialized by lambdas to access each element of the bitfield with the different functions.

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

With this you have to pass an instance of myStruct to the functions. Another method is using std::function and use capturing lambdas:

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

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

    // ...
};

Don't forget that with this, you have to implement copy and move constructors and assignment operators, as the lambda captures this.

Upvotes: 3

Related Questions