Nikita Took
Nikita Took

Reputation: 4012

std::variant with forward declaration

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

Answers (2)

r3mus n0x
r3mus n0x

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

passing_through
passing_through

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

Related Questions