Dealing with circular dependency in std::variant

Viewed 218

I'm trying to deal with circular dependency in following scenario:

I've got a std::variant, say:

//types.h
using Types = std::variant<int, double, std::string, SomeClass>;

SomeClass is a pretty simple thing holding few pointers, with some template logic:

#someclass.h
class SomeClass {
    // few simple members (pointers and an integer)
    
    void use(Types arg); // note usage of Types here

    template<typename T, typename Ts...> // implicitly assuming T == Ts... == Types
    void use(T arg, Ts... tail) {
        use(arg);
        use(tail...);
    }

    SomeClass(const SomeClass&) = default; // works fine
};

Usually I would forward-declare SomeClass before "using Types...", but it can't be done when it comes to std::variant. I also didn't really found a way to forward-declare the "using" directive.

One way I found was forward-declaring SomeClass and using a pointer to it in Types, but I don't like this idea (SomeClass is a really light object with short lifespan, I'd want to keep it out of heap).

Is there any other way (beside pointers) in C++ to solve this one? I'm running out of ideas.

Thanks :)

EDIT:

The issue actually appears only if I'm trying to use Types before really defining SomeClass, see https://godbolt.org/z/4jzhEd

1 Answers

In the live example you provided, all you need to solve the issue is define SomeStruct after SomeClass.

This way your Types variant will no longer have any incomplete types when SomeStruct is defined. In other words, here is the order:

class SomeClass;

using Types = std::variant<..., SomeClass>;

class SomeClass {
   // ... // Types used here, but doesn't need to have all complete types
};

struct SomeStruct {
    Types value;
    // ...
};

See here for a live example.

Related