2013-11-22 28 views
9

Burada bir geçiş tablo olarak bir std::tr1::tuple kullanan bir jenerik devlet makinesinin özel bir uygulama vardır:Boost :: fusion :: vektör çalışma zamanında nasıl bulunur?

template<State StartState, Event TriggerEvent, State TargetState> 
struct transition {...}; 

typedef std::tr1::tuple< transition< ready  , run  , running  > 
         , transition< running , terminate, terminating > 
         , transition< terminating, finish , terminated > 
         > transition_table; 

bir fonksiyonu

template<typename Transitions> 
State find_next_state(State current 
        , Event event 
        , const Transitions& transition_table); 

belirli bir geçiş tablosundaki sonraki halini bulmak için var mevcut durum ve bir olay.

Tüm bu işlemler, 10'dan fazla öğeyi desteklemeyen bu platformun tuple uygulaması dışında geçerlidir. Aynı durum boost::tuple için geçerli gibi görünüyor, bu yüzden bunun yerine boost::fusion::vector çalıştırmaya çalışıyorum. Ancak fusion's find_if'un sadece bir "MPL Lambda Expression" aldığını sanıyorum - ki bu sadece derleme zamanında çalışıyor.

Yukarıdakiler göz önüne alındığında, find_next_state()'u nasıl uygularım?

Not: Sadece GCC 4.1.2 besler, bu yüzden C++ 03 + TR1 ile sıkışmış

Bu özel bir gömülü platformu.

+0

Alternatif bir workarond olarak, belki de tuplleri tupllere paketleyebilirsiniz? – Angew

+1

Çalışma zamanında füzyon dizisi ve işleviyle birlikte çalışacak olan kendi 'find_if 'yazınız nasıl olur? – ForEveR

+0

Neden ilk başta 'tuple' kullanıyorsunuz? 'Geçiş' herhangi bir devlet var mı? Eğer olmazsa, çalışma zamanında yinelemek için 'mpl :: vector' ve' mpl :: for_each' kullanabilirsiniz. – Abyx

cevap

10

Kendi "find_if" nuzu yazmak, "bulunan değeri döndür" kısmı dışında önemsizdir. boost::fusion::vector, heterojen bir kap olduğundan, dönmek için tek bir doğru türü yoktur. Akla gelen bir olası çözüm bulundu değerle çağrılır bir devam işlevini kabul ediyor:

#include <boost/fusion/include/size.hpp> 
#include <boost/fusion/include/at_c.hpp> 

// private implementation details 
namespace detail{ 
// shorthand ... 
template<class S> 
struct fusion_size{ 
    static const unsigned value = 
    boost::fusion::result_of::size<S>::type::value; 
}; 

// classic compile-time counter 
template<unsigned> struct uint_{}; 

template<class Seq, class Pred, class F> 
void find_if(Seq&, Pred const&, F, uint_<fusion_size<Seq>::value>, int) 
{ /* reached the end, do nothing */ } 

template<class Seq, class Pred, class F, unsigned I> 
void find_if(Seq& s, Pred const& pred, F f, uint_<I>, long){ 
    if(pred(boost::fusion::at_c<I>(s))) 
    { 
     f(boost::fusion::at_c<I>(s)); 
     return; // bail as soon as we find it 
    } 
    find_if(s, pred, f, uint_<I+1>(), 0); 
} 
} // detail:: 

template<class Seq, class Pred, class F> 
void find_if(Seq& s, Pred const& pred, F f){ 
    detail::find_if(s, pred, f, detail::uint_<0>(), 0); 
} 

Live example.

int ve long parametreleri yanı sıra 0 argüman sadece zaman I+1 anlam ayrımı içindir == fusion_size<Seq>::value, her iki işlev de aynı derecede geçerli olacaktır. 0 türünün int olması, ilk aşırı yükü (sonuncusu) tercih eder.

+0

Aradığım şeyi, adapte edebildiğim kadar yakın görünüyor. Benim gerçek sorunuma bakmak isteyebileceğiniz geri dönüş değeri. ':) Her zaman bir' State' enum değişkeni döndürmek zorundayım, bu bir parça kek. (Bir eşleşme bulamadığım durumlarda, atmak zorunda olduğum ve önceden tanımlanmış bir değer döndürmek zorunda olduğum varyantlar var, ama bir boole parametresiyle ve daha fazla aşırı yüklenmeyle başa çıkabilirim.) Bu aşırı yükleme olayı görünüyor. biraz aşırı zeki ve bu kod tabanına koymak istediğimden emin değilim, ancak teklifimi yapmak için bunu yaptıktan sonra buna ihtiyacım olup olmadığını göreceğim. – sbi

İlgili konular