Uniform initialization

276
25 января 2018, 19:32

В С++11 появился новый синтаксис инициализации. Вот что по этому поводу пишет Скотт Майерс в книге Effective Modern C++:

class Widget {
public:
  Widget();                                   // default ctor
  Widget(std::initializer_list<int> il);      // std::initializer_list ctor
  …                                           // no implicit conversion funcs
}; 
Widget w1;          // calls default ctor
Widget w2{};        // also calls default ctor
Widget w3();        // most vexing parse! declares a function!    
Widget w4({});      // calls std::initializer_list ctor with empty list
Widget w5{{}};      // ditto  

Если взять его пример, выкинуть лишнее, и добавить печать в конструктор Widget, то окажется что Widget w4({}); и Widget w5{{}}; это не одно и то же:

#include <iostream>
#include <initializer_list>
class Widget{
public:
    Widget(){
    }
    Widget(std::initializer_list<int> l){
        std::cout << "l.size = " << l.size() << std::endl;
    }
};
int main(){
    Widget w4({}); //l.size = 0
    Widget w5{{}}; //l.size = 1
}

Пример

У меня два вопроса:

  1. Скотт нас обманывает?
  2. Что происходит на самом деле?
Answer 1
Widget(std::initializer_list<int> l)//Это initializer-list constructor

Следуя стандарту, он имеет приоритет над другими конструкторами в list-initialization.

Initializer-list constructors are favored over other constructors in list-initialization (16.3.1.7)

Widget w4({}); 

Это direct-initialization. Инициализатор - пустой std::initializer_list.

Widget w4{{}};

Это уже list-initialization. В данном случае direct-list-initialization.

Если список инициализации пуст, то выбирается конструктор по-умолчанию. Если же список инициализации не пуст, то конструктор выбирается в две фазы:

Initially, the candidate functions are the initializer-list constructors (11.6.4) of the class T and the argument list consists of the initializer list as a single argument

If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.

Начинаем первую фазу "ручного" поиска подходящего конструктора.
В первой фазе все аргументы рассматриваются как один initializer list.

Если рассмотреть скобочки в инициализаторе как создание std::initializer_list, то можно ли создать std::initializer_list<int>, передав ему {}? Да, можно

std::initializer_list<int>{{/*вот он наш единственный int со значением 0*/}}`

Всё, подходящий конструктор найден.

То есть в нашем случае

Widget w5{{}};
//приведет к такому -->
Widget w5(std::initializer_list<int>{int{}});

Или еще примеры:

Widget w5{{1}, {2}};//-->
Widget w6(std::initializer_list<int>{int{1}, int{2}});
Widget w7{{1, 2}};//-->
Widget w8(std::initializer_list<int>{std::initializer_list<int>{1, 2}});

Старался объяснить как можно проще, поэтому, изложение "своими словами" может быть не совсем точным.

READ ALSO
NumberLong mongoDb java

NumberLong mongoDb java

Как в записать в mongo строку "1509137313000" что бы в базе она отображалась вот так

305
Java. Создание папок по списку из txt-файла

Java. Создание папок по списку из txt-файла

Я уже всю голову сломалПисал по-разному, но почему то из всего списка создаётся только два (всегда одни и те же StringBufferInputStream и Writer) каталога,...

244
Type-аргументы в lambda-выражении

Type-аргументы в lambda-выражении

Имеем следующий код внутри класса MyClass:

315
Не меняется цвет у компонента JPanel

Не меняется цвет у компонента JPanel

ИтакЕсть класс Window(наследник JFrame), у него такой менеджер компоновки:

291