Search code examples
c++boostc++03boost-mpl

Defining tags and sequences with Boost.MPL in one shot


I have a problem with Boost.MPL and I'm not sure how to approach it. Currently my code looks like this:

struct Definition {
  typedef boost::mpl::int_<5> A;
  typedef boost::mpl::int_<3> B;
  typedef boost::mpl::int_<6> C;
  typedef boost::mpl::int_<1> D;
  // (...)

  typedef boost::mpl::vector<
    A
   ,B
   ,C
   ,D
    // (...)
  > Seq;
};

Here, the number N in mpl::int_< N > denotes some arbitrary decimal number. Then some other code calculates the sum of these numbers up to the type defined by "key", e.g. for Definition::D, the sum is 5 + 3 + 6 (A + B + C). This needs to be done at compile-time. That's why I use mpl::vector and some appropriate meta-programming.

I don't like the current approach since it somehow violates the DRY rule.

I'm wondering whether it would be possible to provide such struct definition without the need to repeat type names in the mpl::vector for Seq type. In other words, I'd probably need a bunch of macros which would allow me to write code like this:

struct Definition {
  FIELD(A, 5);
  FIELD(B, 3);
  FIELD(C, 6);
  FIELD(D, 1);
  // (...)
  GEN_SEQ() // only if really needed
};

And then Definition::A would still refer to boost::mpl::int_<5>, or would at least allow me to access the boost::mpl::int_<5> somehow, and Definition::Seq would give me the appropriate MPL sequence.

Of couse this is just my imagination. The code might look different, I'm just looking for options.


Solution

  • Have you seen metamonad? It has variable abstractions just like you seem to want:

    #include <mpllibs/metamonad/eval_multi_let_c.hpp>
    #include <mpllibs/metamonad/pair.hpp>
    #include <mpllibs/metamonad/syntax.hpp>
    
    #include <boost/mpl/plus.hpp>
    #include <boost/mpl/equal_to.hpp>
    #include <boost/mpl/map.hpp>
    #include <boost/mpl/assert.hpp>
    
    #include <mpllibs/metamonad/metafunction.hpp>
    #include <mpllibs/metamonad/lazy_metafunction.hpp>
    #include <mpllibs/metamonad/returns.hpp>
    #include <mpllibs/metamonad/name.hpp>
    
    #include <boost/mpl/int.hpp>
    #include <boost/mpl/times.hpp>
    #include <boost/mpl/divides.hpp>
    #include <boost/mpl/plus.hpp>
    #include <boost/mpl/minus.hpp>
    #include <boost/mpl/equal_to.hpp>
    
    int main()
    {
        using namespace mpllibs::metamonad::name;
        using boost::mpl::equal_to;
        using boost::mpl::plus;
        using boost::mpl::map;
        using boost::mpl::int_;
    
        using mpllibs::metamonad::eval_multi_let_c;
        using mpllibs::metamonad::syntax;
        using mpllibs::metamonad::pair;
    
        // test_evaluation_of_expression
        static_assert(
          equal_to<
            int_<14>,
            eval_multi_let_c<
              map<
                  pair<a, syntax<int_<5>> >,
                  pair<b, syntax<int_<3>> >,
                  pair<c, syntax<int_<6>> >
              >,
              plus<a, b, c> >::type
          >::value, "Yay, maths still work"
        );
    }