2013-11-22 50 views
9

我這裏有一個專有實現一個通用的狀態機,它使用一個std::tr1::tuple作爲過渡表:如何在運行時在boost :: fusion :: vector中查找元素?

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; 

有一個功能

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

找到轉換表給出的下一個狀態當前狀態和事件。

這一切都工作正常,除了這個平臺的tuple實現不支持超過10個項目。 boost::tuple似乎也是如此,所以我試圖用boost::fusion::vector代替。但它似乎fusion's find_if只需要「一個一元MPL Lambda Expression」 - 我想,這隻能在編譯時工作。

因此,鑑於上述情況,我如何實施find_next_state()

注:

這是一個專用的嵌入式平臺,僅提供GCC 4.1.2,所以我們堅持用C++ 03 + TR1。

+0

作爲另一種工作方式,也許你可以將元組打包到元組中? – Angew

+1

如何編寫自己的'find_if',它將在運行時與融合序列和函數一起使用? – ForEveR

+0

爲什麼你首先使用'tuple'? 「過渡」有沒有任何狀態?如果沒有,你可以使用'mpl :: vector'和'mpl :: for_each'在運行時迭代它。 – Abyx

回答

10

編寫自己的find_if是相當平凡的,除了「返回找到的值」部分。由於boost::fusion::vector是一個異構容器,因此沒有單一的正確類型返回。我想到的一個可能的解決方案是接受被調用與發現價值的延續功能:

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

intlong參數,還有0參數只是用於消除歧義時I+1 == fusion_size<Seq>::value,因爲這兩個功能同樣可行。 0類型爲int首選重載(最後一個)。

+0

這似乎足夠接近我所尋找的,我可以適應它。回想一下你可能想看看我的實際問題的回報價值。 ':''我總是需要返回一個'State'枚舉變量,所以這是小菜一碟。 (如果我沒有找到匹配,那麼我需要拋出的變體以及那些需要返回預定義值的變體,但是我可以使用布爾參數處理這些變量,甚至可以重載)。有點過於聰明,我不確定我想把它放到這個代碼庫中,但是當我按照這個來做我的出價後,我會看看我是否需要它。 – sbi

相關問題