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