2010-12-22 8 views
15

Estoy intentando crear una lista que contenga las permutaciones de una lista de tipos determinada.Permutaciones de una lista de tipos usando boost :: mpl

El siguiente código parece funcionar, aunque sin el resultado deseado, cuando utilizo una lista especificada en lugar de generar una nueva lista quitando de la entrada real. Esto se demuestra por la diferencia entre permutation_helper y broken_helper a continuación.

¿Alguien sabe por qué mpl::remove no parece funcionar como se espera en esta circunstancia?

He usado la declaración para determinar qué devuelve la función, la lista de tipos no es el resultado esperado. Este es el mensaje de la aserción devoluciones para 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> > >::************)’ 

La salida usando permutation_helper es una lista real:

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> > >::************)’ 

Respuesta

5

mpl::remove funciona correctamente. El problema es con su plantilla para permutaciones de listas de singleton: solo captura tipos que son mpl::list s, mientras que el resultado de eliminar tiene otro tipo de secuencia.

Con otras palabras, el resultado de mpl::remove es mpl::equal a la lista unitaria, pero no 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; 
} 

puede solucionar este problema mediante la especialización de la plantilla para la lista unitaria no se basa en el tipo exacto mpl::list , pero en la propiedad para tener una longitud de 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; 
} 

Por cierto,

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

fallará por exactamente los mismos motivos.

  • Lars
-3

Ha intentado poner el código como pertenecientes a los espacios de nombres correspondientes de la biblioteca?

namespace boost 
    { 
    namespace mpl 
    { 
    // code 
    } 
} 

Puede sonar estúpido, pero como ya he resuelto un problema similar (¡pero no estaba usando MPL!).

3

Como una adición a la respuesta que Lars ha publicado:

El algoritmo de permutación dada usando joint_view no parecen funcionar en una lista con un tamaño superior a dos. Lo reemplacé con un mpl :: copy en un front_inserter, y el algoritmo funcionó perfectamente.

#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> > > { }; 
Cuestiones relacionadas