Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::variant with forward declaration

Tags:

c++

c++17

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?

like image 743
Nikita Took Avatar asked Nov 29 '25 16:11

Nikita Took


2 Answers

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(); }
like image 111
r3mus n0x Avatar answered Dec 02 '25 05:12

r3mus n0x


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.

like image 35
passing_through Avatar answered Dec 02 '25 07:12

passing_through



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!