Подтвердить что ты не робот

Почему двойные пустые фигурные скобки {{}} создают std:: initializer_list <double> с одним элементом, а не с нулем?

У меня есть следующий конструктор:

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

который вызывается позже с двойными фигурными фигурными скобками:

MyItem{{}}

Результат l.size() дает 1.

Какова механика за таким поведением?

Кажется, что вложенный {} играет как конструктор по умолчанию для единственного элемента, но я не совсем понимаю, почему и как работает вывод типа.

4b9b3361

Ответ 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. Явное преобразование типа (функциональная нотация))

  1. Аналогично, спецификатор простого типа или 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, который инициализируется значением с помощью пустых фигурных скобок.