Transforming mpl vector with own function

你说的曾经没有我的故事 提交于 2019-12-19 09:09:28

问题


I want to multiply each element in an mpl::vector by an int. First, a metafunction to multiply an int_ with an int.

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

Here are the calls 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 isn't the resulting vector simply a vector<int_<6>, int_<8>>? Am I holding it wrong? Probably the metafunction or the transform is not applied in the right way.


回答1:


Mainly because of some implementation issues in C++03, the writers of the MPL had to use non-obvious techniques for representing sequences, one of which is the usage of types like

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

Instead of simply writing

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

as one would do with variadic templates in C++11 and beyond. Another technique is to create some kind of reverse linked list when you insert stuff in a vector, which is what you're looking 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 specify exactly what is the type of boost::mpl::transform<s,op,in>::type. Actually, it only guarantees that it's 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 does not help you unless you already know the MPL well enough that you don't ask questions on SO about it ;-), so basically it means that it returns a new type that's like a boost::mpl::vector, except for its actual type which may be anything like 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're actually asking whether T and U are precisely the same types. You should now see clearly why this is not what you actually want. Instead, you want to do some kind of deep comparison of those two sequences, which both represent vectors. To check whether two Forward Sequences are equal, you must use the boost::mpl::equal algorithm instead. 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 > ));


来源:https://stackoverflow.com/questions/26672171/transforming-mpl-vector-with-own-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!