2011-01-25 14 views
10

Simple câu hỏi thực sự, hãy để tôi đưa ra một số nền:Có cách nào để thoát khỏi tăng cường không? :: mpl for_each?

Tôi có một mpl::vector các loại trong đó mỗi loại có một id, tại thời gian chạy tôi sử dụng mpl::for_each để lặp qua vector này và tìm ra loại phù hợp cho id cụ thể . Nhưng một khi được tìm thấy, không có điểm nào trong việc tiếp tục vòng lặp, vì vậy - câu hỏi là, có cách nào để thoát ra khỏi nó (mà không ném một ngoại lệ)?

Trả lời

5

Để thực hiện một cái gì đó giống như find_if Tôi đã thay đổi for_each (gọi đó là exec_if) để có một lập luận bool mẫu . Các bool chỉ ra nếu thực hiện nên với các chuỗi tiếp theo, hoặc trong ảnh hưởng trở lại sớm.

#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; 
} 

tôi đã thay đổi này để exec_if, vì vậy bây giờ khi vị phù hợp, sau đó các functor thực hiện sẽ được kích hoạt với các loại - điều này thực hiện chính xác những gì tôi cần.

4

Không, không có cách nào để 'ngắt' một mpl::for_each. Điều đó đang được nói, tôi có thể đã hiểu lầm vấn đề của bạn, nhưng có vẻ như với tôi bạn cần mpl::find_if hơn 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

Tôi cần 'find_if', nhưng phiên bản thời gian chạy thay vì phiên bản meta ở trên. Vấn đề tôi có là '3' chỉ có sẵn khi chạy. – Nim

+2

@ Nim- MPL chỉ hoạt động với các cấu trúc biên dịch thời gian vì các mẫu chỉ có thể được khởi tạo với các giá trị được biết tại thời gian biên dịch. Nếu bạn không biết chỉ mục cho đến khi chạy, bạn sẽ phải sử dụng một số cách tiếp cận khác. – templatetypedef

+0

@templatetypedef, vâng tôi hiểu rằng, cách tiếp cận hiện tại của tôi là cố gắng tìm mã cho 'for_each' và xem liệu tôi có thể hack điều đó, bằng cách nào đó nó lặp lại qua các kiểu là thời gian chạy, vì vậy phải có cách ... – Nim

Các vấn đề liên quan