Reputation: 33
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
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
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