Home > Software design >  Different behaviour in C std::vector construction with gcc and clang
Different behaviour in C std::vector construction with gcc and clang

Time:03-13

In the example below I am expecting v to have 1 element, whos var will be of type Vector and will contain two "int" Variants 10 and 20. This is the behaviour I can see with gcc.

With clang, 'v' contains two elements which are the two "int" Variants 10 and 20.

I think gcc's vector is created via the initializer_list constructor while clang's via the move constructor

Is this a bug in one of the compilers? Do I need to make the Variant's constructors explicit (which will force me to use it like Variant::Vector v{Variant{Variant::Vector{10, 20}}};. Is there any other way to avoid this issue if I want to keep the constructors non explicit?

Tried this code with all gcc and clang versions in https://wandbox.org/ and it behaves the same. Here are some links to try it directly: gcc, clang

#include <iostream>
#include <variant>
#include <vector>

struct Variant
{
    using Vector = std::vector<Variant>;

    Variant(const Vector & value)
    {
        var = value;
    }

    Variant(Vector && value)
    {
        var = std::move(value);
    }

    Variant(int value)
    {
        var = value;
    }

    std::variant<Vector, int> var;
};

int main()
{
    Variant::Vector v{Variant::Vector{10, 20}};

    std::cout << "v size: " << v.size() << ", index: " << v.at(0).var.index() << std::endl;

    return 0;
}

CodePudding user response:

This is CWG 2137, which only gcc implements at present.

Clang bug: https://github.com/llvm/llvm-project/issues/24186

See also C constructor taking an std::initializer_list of size one - this is slightly more complicated in that the initializer list element is constructible from its argument (of the type being initialized), but the diagnosis is the same, and I can't do any better than T.C.'s description:

Clang implemented DR 1467 (brace-initializing a T from a T behaves as if you didn't use braces) but has yet to implement DR 2137 (on second thought, do that only for aggregates).

If you're OK changing your program syntax slightly, you could add another level of braces:

Variant::Vector v{{Variant::Vector{10, 20}}};

Or add parentheses:

Variant::Vector v({Variant::Vector{10, 20}});
  • Related