Search code examples
c++initializer-list

Why does double empty curly braces { { } } create a std::initializer_list<double> with one element, not zero?


I have the following constructor:

MyItem(std::initializer_list<double> l) {
    std::cout << "l size " << l.size() << ")" << std::endl;
}

Which is called later with double curly braces:

MyItem{{}}

The result l.size() gives is 1.

What's the mechanics behind such behavior?

It seems like nested {} plays like a default constructor for the only element, but I don't quite understand why and how type deduction works here.


Solution

  • When you use braces (list-initialization) to initialize the MyItem object, the list constructor you have shown is very greedy.

    These would pass an empty list:

    MyItem foo({});
    MyItem foo{std::initializer_list<double>{}};
    

    This passes a list containing a single element - a value-initialized double (0.0):

    MyItem foo{{}};
    

    This works because there are certain contexts where you can simply use braces in place of a known type. Here, it knows from preferring the list constructor that the given list should contain double.

    For completeness, this looks like it passes an empty list, but it actually value-initializes foo if it has a default constructor (or in special cases, does something almost equivalent). If there's no default constructor, it would choose the list constructor, as shown here.

    MyItem foo{};