4
votes

See the following code from the boost mpl transform documentation:

typedef vector<char,short,int,long,float,double> types;
typedef vector<char*,short*,int*,long*,float*,double*> pointers;
typedef transform< types,boost::add_pointer<_1> >::type result;
BOOST_STATIC_ASSERT(( equal<result,pointers>::value ));

I want to understand the type system of boost::mpl and "how it actually works". As I understand mpl::equal just compares the elements of the following two sequences and not the whole sequence types themselves. I do not understand why the following fails:

BOOST_STATIC_ASSERT(( std::is_same<result,pointers>::value )); //< assert fails

Why is the result type not 100% identical to the "pointers" type? I assume that is somehow because mpl is performing the transformation lazy or the result is just a sequence and not a vector any more? Is it possible to somehow force mpl to do not being lazy any more and get the 100% identical type (I could write a transform function myself with this result, but i want to know how to do it in mpl)?

I tried already some things like e.g. inserting the result in a new vector but without success:

BOOST_STATIC_ASSERT(( std::is_same<
  mpl::insert_range< mpl::vector<>, mpl::begin<mpl::vector<> >::type,
  result >::type, pointers >::value )); //< assert fails too

Also, i tried using a back_insert in the transformation function, which fails too:

typedef transform< types,boost::add_pointer<_1>,
  mpl::back_inserter< mpl::vector< > > >::type result_new;
BOOST_STATIC_ASSERT(( std::is_same<result_new,pointers>::value )); //< fails...

Reading the "documentation" did not help me. So again, is it possible to get the 100% identical type with mpl transform (or any other transforming sequence functions)? And what is the result of the type

result

"in reality" when it not is_same with pointers?

1
I'm guessing that's boost::mpl::vector and not std::vector? Be careful with the using directive, or you might have clashes or in worst case code that's hard to follow and maintain. - Some programmer dude
@JoachimPileborg thx for pointing that out, it is about boost::mpl::vector (the code is from the tutorial and i did not want to modify it). Note that I use the alias namespace mpl = boost::mpl; in the rest of the code. - eci
@llonesmiz Thanks a lot for your code, that really helps in debugging the usage of boost::mpl! So the original type is boost::mpl::vector vs the transformated nested types boost::mpl::v_item. Still i wonder whether i could convert the v_time's back to mpl::vector. At least i could write my own conversion function now... - eci
@llonesmiz After switching from g++ to intel compiler at your code paste, all result types changed to boost::mpl::vector6<char*, short*, int*, long*, float*, double*> which is_same to the pointers type (just use mpl::vector6<> instead of mpl::vector<>) : ). So actually the type gets converted back to vector6<> in that case, which makes it same to the handwritten pointers type. Some thoughts: In the general case (without using variadic types from c++11) the back conversion is not possible as there is always an maximum number N for vectorN<> and a conversion has extra compile costs. - eci

1 Answers

7
votes

Thanks again to @llonesmiz for the code to pretty print the types using typeid(), which helped to understand whats happening.

So it seems the real result type depends on the compiler (probably boost #ifdefs), intel compiler and visual studio convert it back to std::vectorN<> where the maximum N is a predefined number in boost (so it does not work when N is too large). For g++ a mangled type is generated (even 2 different types from my transform calls).

So i guess checking the type via mpl::equal is fine (check the elements of the ranges). If all types should be "really" equivalent (std::is_same holds) i guess you need to convert the result manually to a variadic template class std::tuple.

See http://liveworkspace.org/code/3l8O9K$16 Code Sample

or in short:

template < class T, class R >
struct ToStdTuple;

template < class... TTypes, class X >
struct ToStdTuple< std::tuple< TTypes... >, X >
{
  typedef std::tuple< TTypes..., X > type;
};

and then

// typedef mpl::vector<char,short,int,long,float,double> types;
// typedef mpl::transform< types,boost::add_pointer<mpl::_1> >::type result;

typedef mpl::fold< result, std::tuple<>,
  ToStdTuple< mpl::_1, mpl::_2 > >::type result_normalized;

resulting in

std::tuple<char*, short*, int*, long*, float*, double*>

for all transformation calls