1

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..

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
Palace Chan
  • 8,845
  • 11
  • 41
  • 93

1 Answers1

1

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
{};
TemplateRex
  • 69,038
  • 19
  • 164
  • 304
  • Thank you this is really cool! I'm a bit confused on the lambda though...how come in this case it is not 'strictly necessary'? I think mpl::apply internally uses lambda to convert the placeholder stuff into a metafunction class..does fold do the same? I see the metaforwarding trick at work, very nice too! – Palace Chan Aug 07 '12 at 22:38
  • 1
    @PalaceChan The problems appear if you do a `mpl::fold` on `Sol<_1, lev>`, because then the `_1` inside the outer `mpl::fold` might get confused with the `_1` in the inner fold. If you use `Sol` as a standalone object, then there's no problem, but in general it is safer to wrap placeholders. There was a long thread on the boost mailinglist. http://lists.boost.org/Archives/boost/2012/01/189764.php – TemplateRex Aug 08 '12 at 06:35