【问题标题】:Permutations of a List of Types Using boost::mpl使用 boost::mpl 的类型列表的排列
【发布时间】:2011-05-29 14:34:58
【问题描述】:

我正在尝试创建一个包含给定类型列表排列的列表。

当我使用指定列表而不是通过从实际输入中删除来生成新列表时,下面的代码似乎可以正常工作,尽管没有预期的结果。下面的 permutation_helper 和 broken_helper 之间的区别证明了这一点。

有谁知道为什么mpl::remove 在这种情况下似乎没有按预期运行?

#include <boost/mpl/list.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/joint_view.hpp>
#include <boost/mpl/remove.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/equal.hpp>

namespace mpl = boost::mpl;

struct test_type1 {};
struct test_type2 {};
struct test_type3 {};

template< typename T >
struct permutations;

template <typename value>
struct permutations<mpl::list1< value > >: mpl::list1<mpl::list1< value > > {};

template< typename value, typename T>
struct permutation_helper: 
  mpl::transform< typename permutations< 
      mpl::list1<test_type3> >::type, 
    mpl::push_front< mpl::_1, value> > { };

template< typename value, typename T>
struct broken_helper:
  mpl::transform< typename permutations< 
      mpl::remove<T, value> >::type, 
    mpl::push_front< mpl::_1, value> > { };

template< typename T >
struct permutations: 
  mpl::fold< T,
      mpl::list0<>,
      mpl::joint_view< mpl::_1,
         broken_helper<mpl::_2, T > > > { };

typedef mpl::list2<test_type1, test_type2> typelist;
typedef permutations<typelist>::type perms;

int main() {
  BOOST_MPL_ASSERT(( mpl::equal< perms, typelist > ));
  return 0;
}

我使用断言来确定函数返回的内容,typelist 不是预期的结果。这是断言为 broken_helper 返回的消息:

testcase.cpp: In function ‘int main()’:
testcase.cpp:45: error: no matching function for call to ‘assertion_failed(mpl_::failed************ boost::mpl::equal<boost::mpl::joint_view<boost::mpl::joint_view<boost::mpl::list0<mpl_::na>, boost::mpl::l_end>, boost::mpl::l_end>, boost::mpl::list2<test_type1, test_type2>, boost::is_same<mpl_::arg<-0x00000000000000001>, mpl_::arg<-0x00000000000000001> > >::************)’

使用 permutation_helper 的输出是一个实际的列表:

testcase.cpp: In function ‘int main()’:
testcase.cpp:45: error: no matching function for call to ‘assertion_failed(mpl_::failed************ boost::mpl::equal<boost::mpl::list2<test_type1, test_type2>, boost::mpl::joint_view<boost::mpl::joint_view<boost::mpl::list0<mpl_::na>, boost::mpl::l_item<mpl_::long_<1l>, boost::mpl::l_item<mpl_::long_<2l>, test_type1, boost::mpl::list1<test_type3> >, boost::mpl::l_end> >, boost::mpl::l_item<mpl_::long_<1l>, boost::mpl::l_item<mpl_::long_<2l>, test_type2, boost::mpl::list1<test_type3> >, boost::mpl::l_end> >, boost::is_same<mpl_::arg<-0x00000000000000001>, mpl_::arg<-0x00000000000000001> > >::************)’

【问题讨论】:

    标签: c++ boost metaprogramming boost-mpl


    【解决方案1】:

    mpl::remove 工作正常。问题在于您的单例列表排列模板:它仅捕获 mpl::lists 的类型,而 remove 的结果具有另一种序列类型。

    换句话说,mpl::remove 的结果是 mpl::equal 到单例列表,但不是 std::is_same

    #include <boost/mpl/list.hpp>
    #include <boost/mpl/remove.hpp>
    #include <boost/mpl/equal.hpp>
    
    namespace mpl = boost::mpl;
    
    struct test_type1 {};
    struct test_type2 {};
    
    typedef mpl::list2<test_type1, test_type2> typelist;
    typedef mpl::remove<typelist, test_type1>::type t;
    typedef mpl::list1<test_type2> t_corr;
    
    static_assert(mpl::equal<t,t_corr>::value, "t equals t_corr"); 
    // the following will fail:
    // static_assert(std::is_same<t,t_corr>::value, "t same type as t_corr"); 
    
    int main() {
      return 0;
    }
    

    您可以通过不基于确切类型 mpl::list 而是基于长度为 1 的属性专门针对单例列表的模板来解决此问题:

    #include <boost/mpl/list.hpp>
    #include <boost/mpl/transform.hpp>
    #include <boost/mpl/fold.hpp>
    #include <boost/mpl/push_front.hpp>
    #include <boost/mpl/joint_view.hpp>
    #include <boost/mpl/remove.hpp>
    #include <boost/mpl/assert.hpp>
    #include <boost/mpl/equal.hpp>
    #include <boost/mpl/size.hpp>
    #include <boost/mpl/front.hpp>
    #include <boost/mpl/begin.hpp>
    #include <boost/mpl/next.hpp>
    
    namespace mpl = boost::mpl;
    
    struct test_type1 {};
    struct test_type2 {};
    struct test_type3 {};
    
    template< typename T, typename _ENABLE=void >
    struct permutations;
    
    template <typename T>
    struct permutations<T, 
                typename std::enable_if<mpl::size<T>::value==1>::type>
    {
      typedef typename mpl::list1<T> type;
    };
    
    template< typename value, typename T>
    struct permutation_helper: 
          mpl::transform< typename permutations< 
          mpl::list1<test_type3> >::type, 
        mpl::push_front< mpl::_1, value> > { };
    
    template< typename value, typename T>
    struct broken_helper:
      mpl::transform< typename permutations< 
                typename mpl::remove<T, value>::type >::type, 
              mpl::push_front< mpl::_1, value> > { };
    
    template< typename T >
    struct permutations<T, 
                typename std::enable_if<(mpl::size<T>::value>1)>::type>: 
      mpl::fold< T,
          mpl::list0<>,
          mpl::joint_view< mpl::_1,
          broken_helper<mpl::_2, T > > > { };
    
    typedef mpl::list2<test_type1, test_type2> typelist;
    typedef permutations<typelist>::type perms;
    typedef mpl::list<mpl::list<test_type1, test_type2>, 
              mpl::list<test_type2, test_type1> > perms_corr;
    
    int main() {
      static_assert(mpl::size<perms>::value == 2, "perms has correct size");
      static_assert(mpl::equal<mpl::front<perms>::type,
                       mpl::front<perms_corr>::type>::value, "perms has correct front");
      typedef mpl::next<mpl::begin<perms>::type>::type perms_2nd;
      typedef mpl::next<mpl::begin<perms_corr>::type>::type perms_corr_2nd;
      static_assert(mpl::equal<perms_2nd, perms_corr_2nd>::value, "perms has correct 2nd element");
      return 0;
    }
    

    顺便说一句,

    static_assert(mpl::equal<perms, perms_corr>::value, "perms correct");
    

    会因为完全相同的原因而失败。

    • 拉斯

    【讨论】:

      【解决方案2】:

      作为拉斯发布的答案的附录:

      使用joint_view 的给定置换算法似乎不适用于大小大于2 的列表。我将其替换为 mpl::copy 到 front_inserter,算法运行良好。

      #include <boost/mpl/copy.hpp>
      #include <boost/mpl/front_inserter.hpp>
      
      template< typename T >
      struct permutations<T, typename std::enable_if<(mpl::size<T>::value>1)>::type> : 
        mpl::fold< T,
                   mpl::list0<>,
                   mpl::copy< broken_helper< mpl::_2, T >,
                     mpl::front_inserter< mpl::_1 > > > { };
      

      【讨论】:

        【解决方案3】:

        您是否尝试过将代码归入库的相应命名空间?

        namespace boost
          {
            namespace mpl
            {
             // code
            }
        }
        

        这听起来可能很愚蠢,但因为我已经解决了一个类似的问题(但没有使用 MPL!)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多