2013-11-22 12 views
9

Ich habe hier eine proprietäre Implementierung eines generischen Zustandsmaschine, die ein std::tr1::tuple als Übergangstabelle verwendet:Wie finde ich ein Element in einem boost :: fusion :: vector zur Laufzeit?

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; 

Es gibt eine Funktion

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

den nächsten Zustand in der Übergangstabelle eines bestimmten zu finden aktueller Zustand und ein Ereignis.

Dies funktioniert alles gut, außer für die tuple Implementierung dieser Plattform, die nicht mehr als 10 Elemente unterstützt. Das gleiche scheint für boost::tuple zu gelten, also versuche ich stattdessen boost::fusion::vector zu verwenden. Aber es scheint, fusion's find_if nimmt nur "eine unäre MPL Lambda Expression" - das, ich nehme an, funktioniert nur zur Kompilierzeit.

Also die oben genannten, wie kann ich find_next_state() implementieren?

Hinweis:

Dies ist eine proprietäre Embedded-Plattform, die nur GCC 4.1.2, so dass wir stecken mit C++ 03 + TR1 liefert.

+0

Als Alternative Workarond, könnten Sie vielleicht Tupel in Tupel verpacken? – Angew

+1

Wie wäre es mit einem eigenen 'find_if', der zur Laufzeit mit Fusions-Sequenz und -Funktion arbeitet? – ForEveR

+0

Warum verwenden Sie 'tuple' an erster Stelle? Hat "Übergang" einen Zustand? Wenn nicht, können Sie die 'mpl :: vector' und' mpl :: for_each' verwenden, um in der Laufzeit darüber zu iterieren. – Abyx

Antwort

10

Schreiben Sie Ihre eigenen find_if ist eher trivial, mit Ausnahme der "Rückgabe der gefundenen Wert" Teil. Da ein boost::fusion::vector ein heterogener Container ist, gibt es keinen einzelnen Rechtstyp, der zurückgegeben werden soll. Eine mögliche Lösung, die den Sinn kommt, ist eine Fortsetzung Funktion zu akzeptieren, die mit dem gefundenen Wert aufgerufen wird:

#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.

Die int und long Parameter sowie die 0 Argument sind nur für Begriffsklärung wenn I+1 == fusion_size<Seq>::value, da beide Funktionen gleichermaßen realisierbar wären. 0 vom Typ int macht die erste Überladung (die letzte) bevorzugt.

+0

Das scheint nah genug an dem zu sein, wonach ich suche, dass ich es anpassen kann. Re der Rückgabewert, den Sie möglicherweise auf mein tatsächliches Problem betrachten möchten. ':)' Ich muss immer eine "State" enum Variable zurückgeben, also ist das ein Stück Kuchen. (Für den Fall, dass ich keine passenden finde, gibt es Varianten, die ich werfen muss, und solche, wo ich einen vordefinierten Wert zurückgeben muss, aber diese kann ich mit einem booleschen Parameter und noch mehr Überladung behandeln.) Diese Überladung scheint ein bisschen übermäßig clever und ich bin mir nicht sicher, ob ich es in diese Codebasis schreiben möchte, aber ich werde sehen, ob ich es brauche, nachdem ich es massiert habe, um meine Gebote zu erfüllen. – sbi