2011-01-25 1 views
10

簡単な質問は本当に、私はいくつかの背景を与えてみましょう:boost :: mpl for_eachから抜け出す方法はありますか?

私は、各タイプのIDを持っているタイプのmpl::vectorを持って、実行時に、私はこのベクトルを反復処理し、指定されたidの一致タイプを見つけるためにmpl::for_eachを使用。しかし、一度発見されれば、ループを続けることに意味がないので、質問は、そこから抜け出す方法があるかどうかです(例外を投げずに)?

答えて

5

find_ifのようなものを実装するために、私はboolテンプレート引数を取るように(exec_ifそれを呼び出す)for_eachを変更しました。 boolは、実行が次のシーケンスで行われるべきか、または影響の早期復帰が早いかを示します。

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

私は今、述語が一致したときに、その後、ファンクタは実行するために型にトリガされます、exec_ifにこれを変更する - これは私が必要とするまさにありません。

4

いいえ、mpl::for_eachを「中断する」方法はありません。それは、私はあなたの問題を誤解しているかもしれない、と述べたが、あなたがmpl::for_eachよりmpl::find_ifより多くを必要と私には思われている:

#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

私は 'find_if'が必要ですが、上記のメタではなくランタイムバージョンが必要です。私が持っている問題は、 '3'は実行時にしか利用できないということです。 – Nim

+2

@ Nim-MPLは、コンパイル時に既知の値でしかテンプレートをインスタンス化できないため、コンパイル時の構造体でのみ機能します。ランタイムまでインデックスがわからない場合は、他の方法を使用する必要があります。 – templatetypedef

+0

@templatetypedef、はい私は、現在のアプローチは 'for_each'のコードを見つけようとしていて、それをハックすることができるかどうかを調べるために、何らかの形で実行時が繰り返されるので、方法が必要です。 – Nim

関連する問題