Reputation: 51
I am experimenting with finate state machines and std::variant<..>
std::variant will hold all possible states The states will be defined in State classes.
What I wanted was to have a BaseState class, in which "generic events" should be handled. With derived State classes handling specific states.
struct LightOn;
struct LightOff;
struct Toggle;
struct Reset;
using State = std::variant<LightOn,LightOff>;
using Event = std::variant<Toggle,Reset>;
struct BaseState
{
void on_enter(){Serial.printf("BaseState enter\r\n");};
void on_event (const Reset &r);
};
struct LightOn : BaseState
{
LightOn(){Serial.printf("LightOn constructor\r\n");};
void on_event(const Event &e);
void on_exit(){Serial.printf("LightOn exit\r\n");}
void on_enter(){Serial.printf("LightOn enter\r\n");}
};
struct LightOff : BaseState
{
LightOff(){Serial.printf("LightOff constructor\r\n");};
void on_event(const Event &e);
void on_exit(){Serial.printf("LightOff exit\r\n");}
};
struct Toggle
{
Toggle(){Serial.printf("Struct Toggle\r\n");};
};
struct Reset
{
Reset(){Serial.printf("Struct Reset\r\n");};
};
void LightOn::on_event(const Event &e){Serial.printf("LightOn event\r\n");};
void LightOff::on_event(const Event &e){Serial.printf("LightOff event\r\n");};
void BaseState::on_event(const Reset &r){Serial.printf("BaseState reset\r\n");};
The question I have is in the on_event
function.
There is a specific one on Reset in the Basestate void on_event(const Reset &r);
And a more generic one in LightOn and LightOff void on_event(const Event &e);
(using Event = std::variant<Toggle,Reset>;)
But when I do
LightOn n;
n.on_event(Reset{});
The on_event from LightOn is called, not the one from BaseState.
Is there a way to achieve : Call BaseState function when a BaseState function is available for this specific event ?
Upvotes: 0
Views: 53
Reputation: 144
Similar thing was answered in this question.
The name lookup stops at the sub class (because there is a match there).
You can use using
to introduce the function from the base class (BaseState
) into the same scope. (This will make it follow the usual overloading rules, in this case picking the exact match, which is the function from the base class.)
struct LightOn;
struct LightOff;
struct Toggle;
struct Reset;
using State = std::variant<LightOn,LightOff>;
using Event = std::variant<Toggle,Reset>;
struct BaseState
{
void on_enter(){Serial.printf("BaseState enter\r\n");};
void on_event (const Reset &r);
};
struct LightOn : public BaseState
{
LightOn(){Serial.printf("LightOn constructor\r\n");};
using BaseState::on_event; // <-- Added to the scope
void on_event(const Event &e);
void on_exit(){Serial.printf("LightOn exit\r\n");}
void on_enter(){Serial.printf("LightOn enter\r\n");}
};
struct LightOff : public BaseState
{
LightOff(){Serial.printf("LightOff constructor\r\n");};
void on_event(const Event &e);
void on_exit(){Serial.printf("LightOff exit\r\n");}
};
struct Toggle
{
Toggle(){Serial.printf("Struct Toggle\r\n");};
};
struct Reset
{
Reset(){Serial.printf("Struct Reset\r\n");};
};
void LightOn::on_event(const Event &e){Serial.printf("LightOn event\r\n");};
void LightOff::on_event(const Event &e){Serial.printf("LightOff event\r\n");};
void BaseState::on_event(const Reset &r){Serial.printf("BaseState reset\r\n");};
Also, take a look at Boost compile-time FSM generator example. It seems to accomplish the same goal as yours.
Upvotes: 1