There are already a lot of good answers and ideas, but for the sake of diversity, I will present one more.
The code file for MyClass will be:
struct MemberData { size_t Offset; const char* ID; }; static const MemberData MyClassMembers[] = { { offsetof(MyClass, Member1), "Member1" }, { offsetof(MyClass, Member2), "Member2" }, { offsetof(MyClass, Member3), "Member3" }, }; size_t GetMemberCount(void) { return sizeof(MyClassMembers)/sizeof(MyClassMembers[0]); } const char* GetMemberID(size_t i) { return MyClassMembers[i].ID; } int* GetMemberPtr(MyClass* p, size_t i) const { return (int*)(((char*)p) + MyClassMembers[i].Offset); }
Which then allows you to write the desired constructor as:
MyClass::MyClass(SomeMap& Map) { for(size_t i=0; i<GetMemberCount(); ++i) { *GetMemberPtr(i) = Map[GetMemberID(i)]; } }
And of course, for any other functions that work with all members, you should write similar loops.
There are several problems with this technique:
- Operations with member elements use a run loop rather than other solutions that allow you to perform a detailed sequence of operations.
- It absolutely depends on the fact that each member has the same type. Although this was allowed by the OP, it should still be assessed whether this could change in the future. Some of the other solutions do not have this limitation.
- If I remember correctly,
offsetof is defined only for working with POD types according to the C ++ standard. In practice, I have never seen this fail. However, I have not used all C ++ compilers. In particular, I have never used GCC. Therefore, you will need to test this in your environment to make sure that it really works as intended.
Regardless of whether there are any of these problems, you will need to evaluate your own situation.
Now, believing that this method can be used, there is one nice advantage. These GetMemberX functions can be turned into public static / member functions of your class, thereby giving this universal member access to more places in your code.
class MyClass { public: MyClass(SomeMap& Map); int Member1; int Member2; int Member3; static size_t GetMemberCount(void); static const char* GetMemberID(size_t i); int* GetMemberPtr(size_t i) const; };
And if useful, you can also add the GetMemberPtrByID function to search for the given row identifier and return a pointer to the corresponding member.
One of the drawbacks of this idea so far is that there is a risk that the member may be added to the class, but not to the MyClassMembers array. However, this method can be combined with the xtofl macro solution so that a single list can fill both the class and the array.
changes in title:
#define MEMBERS\ MEMBER( Member1 )\ SEP MEMBER( Member2 )\ SEP MEMBER( Member3 )\ class MyClass { public: #define SEP ; #define MEMBER( name ) int name MEMBERS; #undef MEMBER #undef SEP
and changes to the code file:
const MemberData MyClassMembers[] = { #define SEP , #define MEMBER( name ) { offsetof(MyClass, name), #name } MEMBERS #undef MEMBER #undef SEP };
Note. I left an error here when checking for errors. Depending on how this will be used, you might want to make sure that the bounds of the array are not overflowing with debug modes and / or release modes that will return NULL pointers for bad indexes. Or use exceptions if necessary.
Of course, if you are not worried about the error of checking the boundaries of the array, then GetMemberPtr can actually be replaced with something else that will return a link to the element.