使用boost::mpl生成类型列表的排列组合

15
我试图创建一个包含给定类型列表排列的列表。
下面的代码似乎可以运行,但是当我使用指定的列表而不是通过从实际输入中删除来生成新列表时,它没有产生预期的结果。这可以通过下面的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;
}

我使用assert来确定函数返回的内容,但是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> > >::************)’
3个回答

5

mpl::remove 工作正常。问题在于您用于单例列表排列的模板:它只捕获 mpl::list 类型,而 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;
}

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

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

出现失败的原因完全相同。

  • lars

3
作为Lars发布答案的补充:
使用joint_view的给定排列算法似乎对于大小大于两个的列表不起作用。我用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!)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接