4

我有一个类型列表,我想从中构造包含两个元素的所有组合的列表。例如:

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;

在这里,pair<T1,T2>可能是std::pair<T1,T2>,或mpl::vector<T1,T2>。这该怎么做?当我们考虑到这一点时,我也会有兴趣删除重复项pair<T1, T2> == pair<T2, T1>
谢谢。

4

3 回答 3

6

可以通过调用来计算单个类型int与类型列表的组合列表:mpl::vector<int, long>mpl::fold

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

现在,如果我们将它包装到一个单独的元函数中并为我们得到的所有类型的初始类型列表调用它:

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);

编辑:回答第二个问题:

使结果仅包含唯一元素(在您提到的意义上)有点复杂。首先,您需要定义一个元函数,比较两个元素并返回 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> > >
{};

然后我们需要定义一个元函数,它试图在给定列表中找到给定元素:

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>
{};

现在,这可以用来构建一个新列表,确保没有重复插入:

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;

所有这些都是我的想法,所以它可能需要在这里或那里进行一些调整。但这个想法应该是正确的。


编辑:@rafak 概述的小修正

于 2010-07-23T23:02:04.380 回答
2

很好的问题。有很多有趣的方法可以解决这个问题。这是一个。

所有非限定名称都在mpl命名空间中,除了在 type_traits 库中的_1and_2中的mpl::placeholdersand 。boost::is_same第一个模板是一个辅助类,用于生成由单个元素和给定序列的每个元素组成的所有对的列表。第二个模板将所有结果聚合在一起形成最终序列。请注意,结果不在向量中。您可以使用 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;

旁注:如果您正在阅读本文并想要挑战,请尝试自己回答这个问题。这是对 MPL 的一次很好的尝试。

于 2010-07-24T00:52:50.510 回答
0

我最近一直在自己做一些元编程,你有没有研究过 boost::mpl::set?这将消除重复。至于组合,对我来说这听起来像是映射,那么 boost::mpl::map 呢?请注意,对序列可以采用的类型的限制施加了库限制,尽管可以使用宏进行调整,但您仍然受编译器上限的支配,具体取决于您需要的类型数量处理。

于 2010-07-23T23:47:30.733 回答