I have a following struct:
struct Data
{
std::string firstMember;
std::string secondMember;
std::string thirdMember;
};
I want to select one of the members by string name in constexpr manner, like
Data instance;
auto& member = getMember(instance, "firstMember");
getMember is constexpr function/struct/macros/whatever in question and expression should be (I want it to be) optimized into simple auto& member = instance.firstMember;. My desire here is to be able to call getMember from another constexpr function, which in turn are computing name of particular member –> some kind of compile time reflection.
I know, there is no reflection in C++, therefore it’s OK to register somehow (partially specialize? use some macros magic?) names of members of struct in question, like:
REGISTER_MEMBER(Data, "firstMember", firstMember);
All I want is to have that compile time optimization and do nothing in runtime. Is that possible in C++11 and how?
As noted in the comments, first take a look at
BOOST_FUSION_ADAPT_STRUCT(and friends):This turns your
Datastructure into a sequence usable by Fusion:This prints
"firstData". Change the index to refer to the members in order.There, now we can refer to members at compile-time using a number. But you wanted a name. Also noted in the comments, processing strings is a runtime feature…almost. C++11 gives us
constexpr.It’s a bit tricky, but ultimately it looks like this:
It looks scary but its readable if you take the time to pick it apart.
We have to introduce our own macros to give constant-expression access to the member names; most of the ugly comes from processing Boost.Preprocessor lists. Although Fusion does record the names during adaptation as well (see
boost::fusion::extension::struct_member_name), they are not marked asconstexprso aren’t usable to us, unfortunately.This gives:
Which I think is close to what you were after.
But keep in mind this may not all be necessary: Boost.Fusion may already have what you need. It lives in the area between pure compile-time stuff (Boost.MPL) and regular run-time stuff; adapt your struct and you can already do things like iterate over it (
boost::fusion::for_each).