2011-01-25 21 views
10

pregunta simple en realidad, permítanme dar algunos antecedentes:¿Hay alguna manera de salir de boost :: mpl for_each?

Tengo un mpl::vector de tipos, donde cada tipo tiene un id, en tiempo de ejecución utilizo el mpl::for_each para recorrer este vector y encontrar el tipo de coincidencia para el ID especificado . Pero una vez encontrado, no tiene sentido continuar el ciclo, entonces, la pregunta es, ¿hay alguna manera de salir de ella (sin lanzar una excepción)?

Respuesta

5

Para poner en práctica algo así como find_if he cambiado el for_each (llamándolo exec_if) para tomar un argumento bool plantilla . El bool indica si la ejecución debería con las próximas secuencias, o en el retorno de efectos temprano.

#include <iostream> 

#include <boost/mpl/vector.hpp> 
#include <boost/mpl/is_sequence.hpp> 
#include <boost/mpl/begin_end.hpp> 
#include <boost/mpl/apply.hpp> 
#include <boost/mpl/bool.hpp> 
#include <boost/mpl/next_prior.hpp> 
#include <boost/mpl/deref.hpp> 
#include <boost/type_traits/is_same.hpp> 
#include <boost/mpl/assert.hpp> 

namespace mpl = boost::mpl; 

template< bool done = true > 
struct exec_if_impl 
{ 
    template<typename Iterator, typename LastIterator, typename Pred, typename Exec> 
    static void execute(Iterator*, LastIterator*, Pred const&, Exec const&) 
    { 
    } 
}; 

template<> 
struct exec_if_impl<false> 
{ 
    template<typename Iterator, typename LastIterator, typename Pred, typename Exec> 
    static void execute(Iterator*, LastIterator*, Pred const& f, Exec const& e) 
    { 
    typedef typename mpl::deref<Iterator>::type item; 

    if (!f(static_cast<item*>(0))) 
    { 
     typedef typename mpl::next<Iterator>::type iter; 
     exec_if_impl<boost::is_same<iter, LastIterator>::value> 
     ::execute(static_cast<iter*>(0), static_cast<LastIterator*>(0), f, e); 
    }  
    else 
     e(static_cast<item*>(0)); 
    } 
}; 

template<typename Sequence, typename Pred, typename Exec> 
inline 
void exec_if(Pred const& f, Exec const& e, Sequence* = 0) 
{ 
    BOOST_MPL_ASSERT((mpl::is_sequence<Sequence>)); 

    typedef typename mpl::begin<Sequence>::type first; 
    typedef typename mpl::end<Sequence>::type last; 

    exec_if_impl<boost::is_same<first,last>::value> 
    ::execute(static_cast<first*>(0), static_cast<last*>(0), f, e); 
} 

namespace msg 
{ 
    struct m1 { enum { TYPE = 1 }; static const char* name() { return "m1"; } }; 
    struct m2 { enum { TYPE = 2 }; static const char* name() { return "m2"; } }; 
    struct m3 { enum { TYPE = 3 }; static const char* name() { return "m3"; } }; 
    struct m4 { enum { TYPE = 4 }; static const char* name() { return "m4"; } }; 
    struct m5 { enum { TYPE = 5 }; static const char* name() { return "m5"; } }; 
} 

struct checker 
{ 
    checker(int chk_type) : type(chk_type) {} 

    template <typename Mtype> 
    bool operator()(Mtype* = 0) const 
    { 
    return Mtype::TYPE == type; 
    } 

    int type; 
}; 

struct exec 
{ 
    template <typename Mtype> 
    void operator()(Mtype* = 0) const 
    { 
    std::cout << Mtype::name() << " executed" << std::endl; 
    } 
}; 

int main(void) 
{ 
    typedef mpl::vector<msg::m1, msg::m2, msg::m3, msg::m4, msg::m5> mseq; 

    checker chk(3); 

    exec_if<mseq>(chk, exec()); 

    return 0; 
} 

me cambiaron a este exec_if, por lo que ahora cuando el predicado coincide, entonces el funtor a ejecutar se activará con el tipo - esto es exactamente lo que necesito.

4

No, no hay forma de 'romper' un mpl::for_each. Dicho esto, podría haber entendido mal su problema, pero me parece que necesita mpl::find_if más de mpl::for_each:

#include <boost/mpl/find_if.hpp> 
#include <boost/mpl/vector.hpp> 

template<int N> 
struct Foo { enum { id = N }; }; 

template<int N> 
struct has_nested_id { 
    template<class T> 
    struct apply { 
     static const bool value = (N == T::id); 
    }; 
}; 

int main() 
{ 
    typedef boost::mpl::find_if 
     < 
      boost::mpl::vector<Foo<1>, Foo<2>, Foo<3> >, 
      has_nested_id<3>::apply<boost::mpl::_1> 
     >::type iterator_type; 

    typedef boost::mpl::deref<iterator_type>::type type; // result is Foo<3> 
} 
+0

Necesito un 'find_if', pero una versión en tiempo de ejecución en lugar del meta anterior. El problema que tengo es que '3' solo está disponible en tiempo de ejecución. – Nim

+2

@ Nim- MPL solo funciona con construcciones en tiempo de compilación porque las plantillas solo se pueden crear instancias con valores conocidos en tiempo de compilación. Si no conoce el índice hasta el tiempo de ejecución, tendrá que usar otro enfoque. – templatetypedef

+0

@templatetypedef, sí Entiendo que, mi enfoque actual es tratar de encontrar el código para 'for_each' y ver si puedo hackear eso, de alguna manera itera a través de los tipos que son runtime, así que tiene que haber una forma ... – Nim

Cuestiones relacionadas