如何在运行时在boost::fusion::vector中找到元素?

How to find an element in a boost::fusion::vector at runtime?

提问人:sbi 提问时间:11/22/2013 最后编辑:Xeosbi 更新时间:11/22/2013 访问量:1192

问:

我这里有一个通用状态机的专有实现,它使用 a 作为转换表: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 );

在给定当前状态和事件的转换表中查找下一个状态。

除了该平台的实现不支持超过 10 个项目外,这一切都工作正常。似乎也是如此,所以我正在尝试使用。但似乎 fusion 的find_if只需要“一元 MPL Lambda 表达式”——我想,这只在编译时有效。tupleboost::tupleboost::fusion::vector

那么,鉴于上述情况,我该如何实现?find_next_state()

注意:

这是一个专有的嵌入式平台,只提供GCC 4.1.2,所以我们只能使用C++03+TR1。

C++ 模板-元编程 C++03 boost-fusion

评论

0赞 Angew is no longer proud of SO 11/22/2013
作为另一种工作方式,也许您可以将元组打包为元组?
1赞 ForEveR 11/22/2013
编写自己的,在运行时与融合序列和函数一起使用怎么样?find_if
0赞 Abyx 11/22/2013
你为什么首先使用?有状态吗?如果没有,则可以使用 and 在运行时对其进行迭代。tupletransitionmpl::vectormpl::for_each
0赞 sbi 11/22/2013
@Angew:查看 的 typedef 。如果我这样做,我会要求用户跳过哪些障碍?transition_table
0赞 sbi 11/22/2013
@Abyx:据我所知,Boost.Fusion 是您在遇到“运行时问题”时使用的工具,并且使用仅在运行时已知的值调用。当我今天早上研究它时,我猜我可能会因此更好地使用 Fusion。当然,我可能是错的,但这正是我来这里问的原因。find_next_state()

答:

10赞 Xeo 11/22/2013 #1

编写自己的代码是相当微不足道的,除了“返回找到的值”部分。由于 a 是异构容器,因此没有要返回的单一正确类型。我想到的一个可能的解决方案是接受一个使用找到的值调用的延续函数:find_ifboost::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);
}

活生生的例子。

和参数以及参数只是为了消除 == 时的歧义,因为这两个函数同样可行。 类型使第一个重载(最后一个)成为首选。intlong0I+1fusion_size<Seq>::value0int

评论

0赞 sbi 11/22/2013
这似乎与我正在寻找的东西足够接近,我可以对其进行调整。关于返回值,您可能想看看我的实际问题。 我总是需要返回一个枚举变量,所以这是小菜一碟。(如果我没有找到匹配项,我需要抛出一些变体,以及那些需要返回预定义值的变体,但那些我可以使用布尔参数甚至更多的重载来处理。这个重载的东西似乎有点过于聪明,我不确定我是否要把它放在这个代码库中,但在我按摩它来执行我的命令后,我会看看我是否需要它。:)State