Search code examples
c++c++17variantmonostatestd-variant

What should I use instead of void as one of the alternative types in an variant?


I want to have a variant which may contain type Foo, (disjoint) type Bar, or nothing. Well, naturally, I was thinking of using std::variant<Foo, Bar, void> - but this doesn't seem to work. That is, you can define this type, but if you try to instantiate this you'll fail (GCC 8.2).

So what do I use instead? Some kind of empty struct?


Solution

  • What you really want is a type among the alternatives which has a single possible value - not void, which has no possible values (and is problematic in other ways). In other words: A unit type instead of a bottom type.

    The standard library has defined, as part of <variant>, a "unit type" for this use case: std::monostate (and yes, it's essentially an empty struct). Use it.

    Example:

    #include <variant>
    
    using Foo = int;
    using Bar = double;
    
    int main() {
        std::variant<std::monostate, Foo, Bar> v; 
        v = Foo{}; 
    }
    

    Note that, unlike in the question, the single-possible-value type is the first alternative; this allows the variant to be default-constructible even if Foo isn't. Also, it's potentially cheaper/faster to construct the variant this way than constructing a Foo, even if it is default-constructible.