Bktero
Bktero

Reputation: 812

Return a reference to std::variant that holds non-copyable alternatives

Let's consider this code:

#include <iostream>
#include <variant>

struct Foo {
#if 0
    Foo() = default;
    Foo(const Foo&) = delete;
#endif
    void foo() { std::cout << "foo" << '\n'; }
};

using MyVariant = std::variant<Foo>;

MyVariant& getVariant() {
    static MyVariant variant{Foo{}};
    return variant;
}

int main() {
    auto& variant = getVariant();
    auto& foo = std::get<Foo>(variant);
    foo.foo();
}

It compiles and prints "foo".

If you change the #if 0 by #if 1, making Foo a non copyable class, then the code no longer compiles.

Why do I want Foo to be non copyable? To avoid errors "unexpected copies" with something like auto variant = getVariant(); (note the that & is missing compared to the original code).

I can't fin the correct syntax for this code. Maybe there is none... My purpose is to select an alternative the first time the function is called, and the variant will not be modified later (it will always hold the same alternative).

What do you suggest? Thanks!

Upvotes: 0

Views: 1457

Answers (1)

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136266

Statement MyVariant variant{Foo{}}; requires Foo to have an available copy or move constructor, but there isn't one. When you delete the copy constructor that also makes the move constructor non-declared, so that you need to declare that move constructor explicitly for to compile.

auto foo = std::get<Foo>(variant) requires a copy constructor. Use a reference instead.

A couple of these fixes to make it compile:

struct Foo {
    Foo() = default;
    Foo(const Foo&) = delete;
    Foo(Foo&&) = default; // <--- Declare move constructor.
    void foo() { std::cout << "foo" << '\n'; }
};

using MyVariant = std::variant<Foo>;

MyVariant& getVariant() {
    static MyVariant variant{Foo{}};
    return variant;
}

int main() {
    auto& variant = getVariant();
    auto& foo = std::get<Foo>(variant); // <--- Use reference.
    foo.foo();
}

Upvotes: 4

Related Questions