2010-12-22 55 views
15

我想创建一个包含给定类型列表的排列的列表。类型列表的排列使用boost :: mpl

下面的代码似乎起作用,但没有预期的结果,当我使用指定的列表而不是通过从实际输入中删除来生成新列表时。这可以通过下面的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> > >::************)’ 

回答

5

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

由于完全相同的原因将会失败。

  • 拉尔斯
-3

你有没有尝试把代码为属于库的相应的命名空间?

namespace boost 
    { 
    namespace mpl 
    { 
    // code 
    } 
} 

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

3

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

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