3

The following code does not compile. Why is this restriction, and how can I bypass it? If I replace the variant declaration, it compiles.

struct PPP
{
    int xxx;
    PPP() : x(xxx) {} // error: No matching constructor for initialization of 'std::variant<Inner1, Inner2>'

    struct Inner1
    {
        Inner1(int &x )  : c(x) {}
        int &c;
    };
    struct Inner2
    {
        Inner2(int &x )  : c(x) {}
        int &c;
    };
    struct Inner3 {};

    std::variant<Inner1, Inner2> x;
    // std::variant<Inner1, Inner3> x; // This will cause the code to compile
};
0

1 Answer 1

5

The xxx member is an int.

Inner1 and Inner2 are both constructable from (a reference to) an int, so x(xxx) is ambiguous for std::variant<Inner1, Inner2> as the compiler doesn't know which type you want to construct inside the std::variant.

When you use std::variant<Inner1, Inner3> instead, there is no ambiguity since Inner3 can't be constructed from an int.


UPDATE: As Raymond mentioned in a comment, in this case you can use one of the std::in_place_type_t or std::in_place_index_t constructors of std::variant to tell the compiler which inner type you want to create from the int.

Sign up to request clarification or add additional context in comments.

2 Comments

Note that std::variant<Inner1, Inner2> is perfectly legal. But you have to give the constructor some help. x(std::in_place_type<Inner1>, xxx) or x(std::in_place_type<Inner2>, xxx), depending on which variant you want to initialize.
A simpler alternative is x(Inner1{xxx}). Note that this alternative creates a temporary Inner1 object that is moved into the variant. That's fine for this particular Inner1, but that might cause a problem for more complicated Inner1 implementations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.