3

This is the simplified code:

#include <vector>

class VInitList
{
public:
    explicit VInitList(std::vector<int> v){}
};

int main()
{
    VInitList vil({{}});
}

and compiling with g++ 5.2.1 a get this error:

 error: call of overloaded ‘VInitList(<brace-enclosed initializer list>)’ is ambiguous
     VInitList vil({{}});
                       ^
main.cpp:6:5: note: candidate: VInitList::VInitList(std::vector<int>)
     VInitList(std::vector<int> v){}
     ^
main.cpp:3:7: note: candidate: constexpr VInitList::VInitList(const VInitList&)
     class VInitList
           ^
main.cpp:3:7: note: candidate: constexpr VInitList::VInitList(VInitList&&)

When I saw the compiler error I found out that I have written {{}} by mistake (yeah, don't be mean to me), but I still cannot understand the error. IMHO either the compiler must get rid of the extra {} or return a syntax error.

Then I tried to compile this:

std::vector<int> v = {{{}}};

which works as intended.

3
  • I only glanced over your example, but you got an extra pair of brackets on the code snippet that did compile, maybe that is why? Commented Apr 13, 2016 at 10:06
  • It does not compile in g++ 5.2.1 but it does in Clang 3.7.0 Commented Apr 13, 2016 at 10:22
  • Interesting Q. It seems that, in your scenario, single {} are enough in both the cases. The contained type is int, why to complicate? :-) Commented Apr 13, 2016 at 10:27

1 Answer 1

2

But std::vector<int> v = {{{}}}; doesn't do what you think; it initializes a vector with one int element, initialized to zero. This is because int can be list-initialized:

int i{};   // assert(i == 0)

So std::vector<int> v = {{{}}}; is parsed as:

std::vector<int> v = {{{}}};
                       ^-- int
                      ^-- initializer_list<int>
                     ^-- vector<int>

Likewise, if you write

VInitList vil{{{}}};
               ^-- int
              ^-- vector<int>
             ^-- VInitList 

the contained vector<int> has 1 element, initialized to zero. (The initializer_list<int> stage can be omitted because the vector(initializer_list<int>) constructor is non-explicit).

So VInitList vil({{}}); could be parsed as:

VInitList vil({{}});
               ^-- int
              ^-- vector<int>

or as

VInitList vil({{}});
               ^-- vector<int>
              ^-- VInitList

In the first case the vector has 1 element; in the second case it's empty. It's just as well that gcc rejects your code.

Clang only parses it as the former; I'm not sure which is correct.

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

2 Comments

very interesting, I didn't know int can be list-initialized. why is that possible? and what for?
@FrankS101 consistency, mainly - it means you can use {} or = {} anywhere you want an object initialized to its "empty" state. Note that in C++98 you could use () in places it wouldn't be confused with a function declaration, e.g. member initializers: struct S { int i; S() : i() {} };

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.