2010-12-22 62 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> > > { };