Reputation: 1055
I am reading about implementation of state machines using variants. I try to create a construction that take a variant parameter to initialize the state. However whent the constructor is defined , I get a warning that this is recognized as function declaration.
Moreover when I try to define a setter for the state, compiler error is generated when try to call this
Here is the code
#include "pch.h"
#include <iostream>
#include <variant>
#include <cassert>
struct DoorState
{
struct DoorOpened {};
struct DoorClosed {};
struct DoorLocked {};
using State = std::variant<DoorOpened, DoorClosed, DoorLocked>;
DoorState()
{
}
DoorState(State & state)
{
m_state = state;
}
void open()
{
m_state = std::visit(OpenEvent{}, m_state);
}
void close()
{
m_state = std::visit(CloseEvent{}, m_state);
}
void lock()
{
m_state = std::visit(LockEvent{}, m_state);
}
void unlock()
{
m_state = std::visit(UnlockEvent{}, m_state);
}
struct OpenEvent
{
State operator()(const DoorOpened&) { return DoorOpened(); }
State operator()(const DoorClosed&) { return DoorOpened(); }
// cannot open locked doors
State operator()(const DoorLocked&) { return DoorLocked(); }
};
struct CloseEvent
{
State operator()(const DoorOpened&) { return DoorClosed(); }
State operator()(const DoorClosed&) { return DoorClosed(); }
State operator()(const DoorLocked&) { return DoorLocked(); }
};
struct LockEvent
{
// cannot lock opened doors
State operator()(const DoorOpened&)
{
std::cout << "DoorOpened" << std::endl;
return DoorOpened();
}
State operator()(const DoorClosed&) { return DoorLocked(); }
State operator()(const DoorLocked&) { return DoorLocked(); }
};
struct UnlockEvent
{
// cannot unlock opened doors
State operator()(const DoorOpened&) { return DoorOpened(); }
State operator()(const DoorClosed&) { return DoorClosed(); }
// unlock
State operator()(const DoorLocked&) { return DoorClosed(); }
};
void set(State state)
{
}
State m_state;
};
int main()
{
//DoorState s(DoorState::DoorOpened);
DoorState s;
s.set(DoorState::DoorOpened);
s.lock();
return 0;
}
Upvotes: 2
Views: 4109
Reputation: 2695
In
s.set(DoorState::DoorOpened);
you are passing a type, you should pass an instance of a type, try
s.set(DoorState::DoorOpened{});
after this change I was able to compile in MSVC 2019 (16.1.3)
Edit: This is an edit to address Scheff and Jarod24 comments, there would have been a case of most vexing parse if we were to uncomment the constructor and write
DoorState s(DoorState::DoorOpened());
This could have been fixed using the uniform initialization syntax, see e.g. https://arne-mertz.de/2015/07/new-c-features-uniform-initialization-and-initializer_list/
DoorState s{DoorState::DoorOpened{}};
This would have solved the most vexing parse issue but created a new issue: DoorState::DoorOpened{}
would have been a temporary and it could have never been bound to the input argument of the ctor:
DoorState(State& state)
we then would have needed to change it to
DoorState(const State& state)
Thanks again to Jarod and Scheff for pointing out the issue.
Upvotes: 2