【问题标题】:Combination of types using boost::mpl使用 boost::mpl 的类型组合
【发布时间】:2010-07-23 20:35:14
【问题描述】:

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

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&lt;T1,T2&gt; 可以是 std::pair&lt;T1,T2&gt;mpl::vector&lt;T1,T2&gt;。 这该怎么做? 当我们考虑到 pair&lt;T1, T2&gt; == pair&lt;T2, T1&gt; 时,我也有兴趣删除重复项。
谢谢。

【问题讨论】:

    标签: c++ metaprogramming boost-mpl


    【解决方案1】:

    单个类型int与类型列表mpl::vector&lt;int, long&gt;的组合列表可以通过调用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 概述的小修正

    【讨论】:

    • 非常感谢!我不知道如何使用 mpl::lambda。有了您在回答中提供的有关 mpl 的材料,我想我现在可以回答我自己的问题了。
    • 注意:我无法编辑您的帖子,所以这里是我需要的一些小改动:在list_doesnt_have_element 中,将end&lt;List&gt; 替换为typename end&lt;List&gt;::type,与find_if 同上。另外,我必须将BOOST_STATIC_ASSERT(is_same&lt; 替换为BOOST_MPL_ASSERT((mpl::equal&lt;,并在最后加上一个括号。如果有人可以编辑答案,我将删除此评论。
    【解决方案2】:

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

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

    【讨论】:

    • 优秀的答案!谢谢。我不知道意见。所以我尝试用transform_view 替换fold 中的transform,它似乎按预期工作。但如果我在single_combo 中更改转换,则不会(尽管如果直接使用它可以工作,而不是来自combo)。你有解释吗?
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-29
      • 1970-01-01
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多