Почему двойные пустые фигурные скобки {{}} создают std:: initializer_list <double> с одним элементом, а не с нулем?
У меня есть следующий конструктор:
MyItem(std::initializer_list<double> l) {
std::cout << "l size " << l.size() << ")" << std::endl;
}
который вызывается позже с двойными фигурными фигурными скобками:
MyItem{{}}
Результат l.size() дает 1.
Какова механика за таким поведением?
Кажется, что вложенный {} играет как конструктор по умолчанию для единственного элемента, но я не совсем понимаю, почему и как работает вывод типа.
Ответы
Ответ 1
Когда вы используете фигурные скобки (инициализация списка) для инициализации объекта MyItem
, созданный вами конструктор списка очень жадный.
Они будут содержать пустой список:
MyItem foo({});
MyItem foo{std::initializer_list<double>{}};
Это передает список, содержащий один элемент - инициализированный значением double
(0.0):
MyItem foo{{}};
Это работает, потому что есть определенные контексты, где вы можете просто использовать фигурные скобки вместо известного типа. Здесь он знает, предпочитая конструктор списка, чтобы данный список содержал double
.
Для полноты, похоже, что он передает пустой список, но на самом деле value-initializes foo
, если он имеет конструктор по умолчанию (или в особых случаях делает что-то почти эквивалентное). Если нет конструктора по умолчанию, он будет выбирать конструктор списка как показано здесь.
MyItem foo{};
Ответ 2
Это выражение
MyItem{{}}
обозначает явное преобразование типа (функциональная нотация).
В соответствии со стандартом С++ (5.2.3. Явное преобразование типа (функциональная нотация))
- Аналогично, спецификатор простого типа или typename-specifier, за которым следует braced-init-list создает временный объект указанного типа direct-list-initialized (8.5.4) с указанным скобками-init-list, и его значение заключается в том, что временный объект является значением prvalue.
Класс MyItem имеет конструктор списка инициализаторов конверсий
MyItem(std::initializer_list<double> l) {
std::cout << "l size " << l.size() << ")" << std::endl;
}
который выбирается для явного преобразования типов. На самом деле это эквивалентно вызову
MyItem( {{}} );
Таким образом, конструктор получает список инициализаций с одним элементом
{ {} }
Скалярный объект типа double может быть инициализирован пустыми фигурными скобками {}
.
В результате выражение создает временный объект типа MyItem
, который инициализируется списком инициализатора, который содержит один элемент типа double, который инициализируется значением с помощью пустых фигурных скобок.