Search code examples
c++macrosmetaprogramming

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


I am working on an application with a message based / asynchronous agent-like architecture. There will be a few dozen distinct message types, each 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/meta-program that would allow calculating the number of data members within the 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 could boost::mpl::vector allow me to accomplish this type of calculation?


Solution

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

    You could store all types in a mpl::vector along in your classes but then you face the problem of how to turn them into members with appropriate names (which you cannot achieve without some macro hackery).

    Using std::tuple instead of PODs is a solution that generally works but makes for incredible messy code when you actually work with the tuple (no named variables) unless you convert it at some point or have a wrapper that forwards accessors onto the tuple member.

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

    A 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 didn't test it so there could be bugs.