Круговая зависимость C ++ от класса tinyfsm — предварительные объявления не работают

У меня проблемы со следующим кодом:

#include "tinyfsm.hpp"
struct Event : tinyfsm::Event { };

struct State1;
struct State2;

struct Fsm : tinyfsm::Fsm<Fsm> {
virtual void react(Event const &) { }
virtual void entry() { }
void exit() { };
virtual ~Fsm() { }
};

struct State1 : Fsm{
void react(Event const & event) override { transit<State2>(); }
void entry() override { }

};

struct State2 : Fsm{
void react(Event const & event) override { transit<State1>(); }
void entry() override { }
};

FSM_INITIAL_STATE(Fsm, State1)

Компилятор выдает сообщение:

"..\src\tinyfsm.hpp", line 134: cc0513:  error: a value of type "State2 *" cannot be assigned to an entity of type "Fsm *"current_state_ptr = &_state_instance<S>::value;
^
detected during instantiation of "void tinyfsm::Fsm<F>::transit<S>() [with F=Fsm, S=State2]" at line 31 of "..\src\testbed.cpp"

Я почти уверен, что это потому, что компилятор не понимает, что State2 наследуется от Fsm.

Есть ли способ разорвать циклическую зависимость или предоставить компилятору соответствующую информацию, чтобы он правильно компилировался?

Я использую ccblkfn.exe версии 8.12.0.0 (работаю на процессоре blackfin)

Я думаю, что это может быть ошибка компилятора, так как этот код прекрасно компилируется на g ++ 6.3.0.

1

Решение

Ошибка компиляции, по-видимому, из-за:

struct Fsm : tinyfsm::Fsm<Fsm>

Это объявляет struct названный Fsm в глобальном пространстве имен.

Заголовок определяет тип с тем же именем в tinyfsm Пространство имен. Вызов макроса

FSM_INITIAL_STATE(Fsm, State1)

Расширяется до этого объявления макроса:

#define FSM_INITIAL_STATE(_FSM, _STATE)                               \
namespace tinyfsm {                                                   \
template<> void Fsm< _FSM >::set_initial_state(void) {              \
current_state_ptr = &_state_instance< _STATE >::value;            \
}                                                                   \
}

Это заканчивается расширением до:

namespace tinyfsm {
template<> void Fsm<Fsm>::set_initial_state(void) {
current_state_ptr = &_state_instance< _STATE >::value;
}
}

Что вы думаете <Fsm> часть заканчивает тем, что обращалась к? Не твой класс, а Fsm шаблон в пространстве имен tinyfsm. Хиллярность наступает.

Есть несколько простых способов устранить эту неоднозначность.

FSM_INITIAL_STATE(::Fsm, State1)

Макрос теперь вставляет ссылку на ваш Fsm структура в глобальном пространстве имен.

Другой способ — просто переименовать Fsm класс к чему-то еще.

Третий способ — это поместить все ваши классы в свое собственное пространство имен (за пределами вашего пространства имен).

namespace fsmimpl {

// Your existing class declarations

}

FSM_INITIAL_STATE(fsmimpl::Fsm, State1)
1

Другие решения

Других решений пока нет …