Convert vector mpl with custom function

I want to multiply each element in mpl::vector

by int

. First, there is a metafunction for multiplying a int_

with a int

.

template <int i>
struct multiply_scalar
{
    template<typename T> struct apply
    {
        typedef int_<(T::value * i)> type;
    };
};

      

Here are the challenges I want to make.

typedef vector<int_<3>, int_<4> > my_vec;
typedef typename transform< my_vec,  multiply_scalar<2> >::type my_vec_2;

typedef vector<int_<6>, int_<8> > my_vec_3;

BOOST_MPL_ASSERT(( boost::is_same< my_vec_2, my_vec_3 > )); //Fails
//type of my_vec2 is: boost::mpl::v_item<mpl_::int_<8>, boost::mpl::v_item<mpl_::int_<6>, boost::mpl::vector0<mpl_::na>, 0>, 0>

      

Why is the resulting vector not simple vector<int_<6>, int_<8>>

? Am I holding it wrong? Probably the metafunction or transformation is not being applied correctly.

+3


source to share


1 answer


Mainly due to some implementation issues in C ++ 03, the MPL authors had to use non-obvious methods to represent sequences, one of which is the use of types such as

boost::mpl::vector0<>
boost::mpl::vector1<T>
boost::mpl::vector2<T, U>
... etc

      

Instead of just writing

boost::mpl::vector<>
boost::mpl::vector<T>
boost::mpl::vector<T, U>

      

as with variational templates in C ++ 11 and beyond. Another technique is to create a kind of inverse linked list when you insert stuff into a vector, which is what you look at in your example:

boost::mpl::v_item<mpl_::int_<8>, // 2nd element
    boost::mpl::v_item<mpl_::int_<6>, // 1st element
        boost::mpl::vector0<mpl_::na>, 0>, 0> // empty list

      



Because of this, the documentation for boost::mpl::transform

does not indicate exactly what a type is boost::mpl::transform<s,op,in>::type

. In fact, this only ensures that it is a type equivalent to

typedef lambda<op>::type f;
typedef lambda<in::operation>::type in_op;

typedef fold<
      s
    , in::state
    , bind< in_op, _1, bind<f, _2> >
    >::type r; // <-- the return type is equivalent to this r

      

This probably won't help you unless you already know MPL well enough, you don't ask questions about it ;-), so it basically means it returns a new type similar to boost::mpl::vector

, except for its actual type, which might be such as I showed above. In particular, this type is guaranteed to be a model of the Forward Sequence concept .

When you use boost::is_same<T, U>

, you are really asking if T

and U

exactly the same types. Now you should see clearly why this is not what you really want. Instead, you want to do some kind of deep comparison of these two sequences, which both represent vectors. To check if two Forward Sequences are equal, you must use an boost::mpl::equal

algorithm. The following will work:

#include <boost/mpl/assert.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/vector.hpp>


using namespace boost::mpl;
template <int i>
struct multiply_scalar
{
    template<typename T> struct apply
    {
        typedef int_<(T::value * i)> type;
    };
};

typedef vector<int_<3>, int_<4> > my_vec;
typedef transform< my_vec,  multiply_scalar<2> >::type my_vec_2;

typedef vector<int_<6>, int_<8> > my_vec_3;

BOOST_MPL_ASSERT(( boost::mpl::equal< my_vec_2, my_vec_3 > ));

      

+5


source







All Articles