Type combination using boost :: mpl

I have a list of types from which I want to build a list of all combinations with two elements. For instance:

namespace mpl = boost::mpl; typedef mpl::vector<int, long> typelist; // mpl magic... // the wanted list is equivalent to: typedef mpl::vector<pair<int, int>, pair<int, long>, pair<long, int>, pair<long, long> > combinations; 

Here pair<T1,T2> can be std::pair<T1,T2> or mpl::vector<T1,T2> . How to do it? I would also like to remove duplicates, given that pair<T1, T2> == pair<T2, T1> .
Thanks.

+4
source share
3 answers

The list of combinations of the same int type with the list of types mpl::vector<int, long> can be calculated by calling mpl::fold :

 typedef fold< mpl::vector<int, long>, vector<>, push_back<mpl::_1, std::pair<int, mpl::_2> > >::type list_of_pairs; 

Now, if we wrap this in a separate meta-function and output it for all types of the source list, we get:

 typedef mpl::vector<int, long> typelist; template <typename T, typename Result> struct list_of_pairs : mpl::fold<typelist, Result, mpl::push_back<mpl::_1, std::pair<T, mpl::_2> > > {}; typedef mpl::fold< typelist, mpl::vector<>, mpl::lambda<list_of_pairs<mpl::_2, mpl::_1> > >::type result_type; BOOST_MPL_ASSERT( mpl::equal<result_type, mpl::vector4< std::pair<int, int>, std::pair<int,long>, std::pair<long,int>, std::pair<long,long> > >::value); 

EDIT: answer to the second question:

Bringing a result containing only unique elements (in the sense that you spoke about) is a bit more active. First you need to define a meta function that compares two elements and returns mpl :: true_ / mpl :: false _:

 template <typename P1, typename P2> struct pairs_are_equal : mpl::or_< mpl::and_< is_same<typename P1::first_type, typename P2::first_type>, is_same<typename P1::second_type, typename P2::second_type> >, mpl::and_< is_same<typename P1::first_type, typename P2::second_type>, is_same<typename P1::second_type, typename P2::first_type> > > {}; 

Then we need to define a meta function that tries to find the given element in this list:

 template <typename List, typename T> struct list_doesnt_have_element : is_same< typename mpl::find_if<List, pairs_are_equal<mpl::_1, T> >::type, typename mpl::end<List>::type> {}; 

Now it can be used to create a new list so that no duplicates are inserted:

 typedef mpl::fold< result_type, mpl::vector<>, mpl::if_< mpl::lambda<list_doesnt_have_element<mpl::_1, mpl::_2> >, mpl::push_back<mpl::_1, mpl::_2>, mpl::_1> >::type unique_result_type; 

All this is from the top of the head, so you may need some kind of tuning here or there. But the idea must be right.


EDIT: minor fixes described by @rafak

+6
source

Great question. There are many interesting ways to solve this problem. Here is one of them.

All unqualified names are in the mpl namespace, with the exception of _1 and _2 , which are in mpl::placeholders and boost::is_same , which are in the type_traits library. The first template is a helper class for creating a list of all pairs consisting of one element and each element of a given sequence. The second template combines all the results together to form the final sequence. Please note that the results are not in a vector. You can do this easily with mpl :: copy.

 template <class Elem, class Seq> struct single_combo { typedef typename transform<Seq ,lambda< std::pair<Elem, _1> > >::type type; }; template <class Seq> struct combo { typedef typename unique<Seq, is_same<_1,_2> >::type U; typedef typename fold< typename transform<U ,lambda< single_combo<_1, U> > >::type ,empty_sequence ,lambda< joint_view<_1,_2> > >::type type; }; typedef typename combo<typelist>::type combinations; 

Note: if you are reading this and want to try it, try to answer this question yourself. This is a great dive into the MPL.

+2
source

Recently, I have a little metaprogrammed myself, have you looked in boost :: mpl :: set? This will eliminate duplicates. As for the combinations, it sounds to me like mapping, but what about boost :: mpl :: map? Remember that there are library limits that overlap with the limits of types that sequences can execute, although this can be adjusted with a macro, you are still at the mercy of your compiler's upper limit, depending on the number of types you need to handle.

0
source

Source: https://habr.com/ru/post/1316713/


All Articles