Reputation: 4012
I'm working on a simple state machine similar to this.
I'm trying to encode my states in separate classes which looks like:
// class StateA; (1)
// class StateB; (2)
using State = std::variant<StateA, StateB>;
class StateA {
State handle(/* some params */) { return StateB(); };
};
class StateB {
State handle(/* some params */){ return StateA(); };
};
Now my variant knows nothing about StateA and StateB, which results into use of undeclared identifier 'StateA'
. If I uncomment (1) and (2) and have a forward declaration, then I get incomplete type 'StateA' used in type trait expression
Is there a way to have a variant with classes, that has variant in it?
Upvotes: 2
Views: 3519
Reputation: 6154
You need to make sure that both of your variant
members are complete types at the point where you use it, for example by moving the definitions for handle
methods outside of your classes:
#include <variant>
class StateA;
class StateB;
using State = std::variant<StateA, StateB>;
class StateA {
State handle(/* some params */);
};
class StateB {
State handle(/* some params */);
};
State StateA::handle() { return StateB(); }
State StateB::handle() { return StateA(); }
Upvotes: 8
Reputation: 1941
Maybe you can use dynamic polymorphism as a more convenient design: store std::unique_ptr<State>
and use std::make_unique<StateX>()
to initialize it with a StateX
derived from State
where the latter is an abstract base class.
std::unique_ptr
allows forward-declared types but std::make_unique
still requires the trick from the accepted answer as it needs StateX
's size and constructor.
Upvotes: 1