Search code examples
c++templatestemplate-meta-programmingboost-mpl

using mpl::fold with a placeholder and my own struct mishap


I have the following primary template:

template<size_t pos, size_t lev>
struct Sol;

and I specialize it for some pos values like so:

template<size_t lev>
struct Sol<0, lev>
{
    static const mpl::vector_c<size_t, 4, 6> jumps;
    static const size_t value =
        mpl::fold<jumps, mpl::integral_c<size_t, 0>, 
                  mpl::plus<Sol<_1, lev-1>::value, 
                            Sol<_2, lev-1>::value> >::type::value;
}

but I get that Sol expected size_t and got mpl_::_1. I know in this case I could probably omit this fold thing im trying to do and just declare value to be the sum of the one level lower values of the other two Sol structs for pos of 4 and 6..but I was wondering if this could be repaired in case the vector_c was a bit long to type out?

Thanks..


Solution

  • The code below will do what you want. I've made a few changes.

    First, I wrapped the pos non-type template parameter with a mpl::integral_c. In general, when using Boost.MPL, it is advised to wrap all your non-type template parameters. This way, you never have to distinguish them later on.

    Second, I used template metafunction forwarding. What this means is that instead of defining a template data member value inside Sol, I simply derive Sol from a Boost.MPL template that contains that value. This will save you typing ::type::value all over the place. Use good indentation to make the code easier to read.

    Third, I wrapped your call to mpl::plus inside mpl::fold with a boost::mpl::lambda. This is not stricly necessary for the code you gave, but it will be if you use Sol itself inside another mpl::fold expression with other placeholder arguments (the lambda wrapping will delay evaluation until the entire template has been parsed).

    Fourth, I made a full specialization to stop the recursion on your lev parameter. BTW, if you ever start doing compile-time computation ons lev, the same advise applies: wrap it first into a mpl::integral_c.

    #include <boost/mpl/fold.hpp>
    #include <boost/mpl/integral_c.hpp>
    #include <boost/mpl/lambda.hpp>
    #include <boost/mpl/placeholders.hpp>
    #include <boost/mpl/plus.hpp>
    #include <boost/mpl/vector_c.hpp>
    
    namespace mpl = boost::mpl;
    using namespace mpl::placeholders;
    
    // primary template
    template<typename pos, size_t lev>
    struct Sol;
    
    // partial specialization for zero position
    template<size_t lev>
    struct Sol< mpl::integral_c<size_t, 0>, lev>
    :
            mpl::fold<
                    mpl::vector_c<size_t, 4, 6>, 
                    mpl::integral_c<size_t, 0>,
                    mpl::lambda<
                            mpl::plus<
                                    Sol<_1, lev-1>, 
                                    Sol<_2, lev-1>
                            > 
                    > 
            >        
    {};
    
    // full specialization for zero position and level
    template<>
    struct Sol< boost::mpl::integral_c<size_t, 0>, 0>
    :
            boost::mpl::integral_c<size_t, 0> // or whatever else you need
    {};