我这里有一个通用状态机的专有实现,它使用std::tr1::tuple
作为转换表:
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 :(得分: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);
}
在int
== long
时,0
和I+1
参数以及fusion_size<Seq>::value
参数仅用于消除歧义,因为这两个函数都是同样可行。 0
类型int
使第一个重载(最后一个)成为首选。