C ++ macro / metaprogram to determine the number of members at compile time

I am working on a message-based / asynchronous agent-like architecture application. There will be several dozen different types of messages, each of which is represented by C ++ types.

class message_a { long long identifier; double some_value; class something_else; ...//many more data members } 

Is it possible to write a macro / metaprogram that would calculate the number of data members in a class at compile time?

//eg:

 class message_b { long long identifier; char foobar; } bitset<message_b::count_members> thebits; 

I am not familiar with C ++ meta-programming, but I can increase :: mpl :: vector Let me do this type of computation?

+4
source share
5 answers

No, in C ++ there is no way to find out the names of all the participants or how many members are actually there.

You can store all types in mpl::vector along with your classes, but then you are faced with the problem of how to turn them into members with the corresponding names (which you cannot achieve without any hacking).

Using std::tuple instead of POD is a solution that usually works, but it creates incredible messy code when you actually work with a tuple (without variable names) if you don't convert it at any moment or don't have a shell, which forwards accessors to a member of the tuple.

 class message { public: // ctors const int& foo() const { return std::get<0>(data); } // continue boiler plate with const overloads etc static std::size_t nun_members() { return std::tuple_size<data>::value; } private: std::tuple<int, long long, foo> data; }; 

Solution with Boost.PP and MPL:

 #include <boost/mpl/vector.hpp> #include <boost/mpl/at.hpp> #include <boost/preprocessor.hpp> #include <boost/preprocessor/arithmetic/inc.hpp> struct Foo { typedef boost::mpl::vector<int, double, long long> types; // corresponding type names here #define SEQ (foo)(bar)(baz) #define MACRO(r, data, i, elem) boost::mpl::at< types, boost::mpl::int_<i> >::type elem; BOOST_PP_SEQ_FOR_EACH_I(MACRO, 0, SEQ) }; int main() { Foo a; a.foo; } 

I did not test it so that there might be errors.

+3
source

as others have said, you need Boost.Fusion and BOOST_FUSION_DEFINE_STRUCT . You will need to define your structure once using an unused but simple syntax. As a result, you get the required count_members (usually called size ) and much more flexible than just.

Your examples:

Definition:

 BOOST_FUSION_DEFINE_STRUCT( (), message_a, (long long, identifier), (double, some_value) ) 

using:

 message_a a; size_t count_members = message_a::size; 
+4
source

Plain structs does not support member counting, but boost :: fusion offers a good way to declare a structure that is countable and iterative.

0
source

Something like this might come close to you:

 struct Foo { Foo() : a(boost::get<0>(values)), b(boost::get<1>(values)) {} int &a; float &b; typedef boost::tuple<int,float> values_t; values_t values; }; 
0
source

There are a few answers that simply say that this is not possible, and if you had not contacted magic_get, I would agree with them. But magic_get shows, to my surprise, that this is indeed possible in some cases. This proves that proving that something is impossible is more difficult than proving that something is possible!

The short answer to your question would be to use objects in magic_get directly, rather than redefining them yourself. In the end, even looking at the pre-Boost version of the code, it's not entirely clear how this works. At some point in the comments, he mentions something about constructor arguments; I suspect that this is the key because the arguments of the regular function can be read , so maybe it counts the number of arguments needed for the parenthesis-initialization of the structure.This indicates that this is possible only when using simple old structures, and not objects with by your own methods.

Despite all this, I would suggest using a reflection library, as others have suggested. The good one that I often recommend is the Google protobuf library, which has reflection and serialization along with support for multiple languages. However, it is intended only for data-only objects (such as plain old structures, but with vectors and strings).

0
source

All Articles