C ++ 11 — конструктор C ++ std :: initializer_list

В коде так:

#include <iostream>
#include <initializer_list>
#include <string>

struct A
{
A() { std::cout << "2" << std::endl; }
A(int a) { std::cout << "0" << std::endl; }
A(std::initializer_list<std::string> s) { std::cout << "3" << std::endl; }
A(std::initializer_list<int> l) { std::cout << "1" << std::endl; }
};

int main()
{
A a1{{}};
}

Почему это называется std::initializer_list<int> спецификация конструктора?
Это сгенерирует ошибку компиляции неоднозначности, если мы определим, например, конструктор с std::initializer_list<double>, Каковы правила такой конструкции и почему она так конкретна? std::initializer_list с номером в качестве аргумента шаблона?

12

Решение

Если класс имеет конструктор списка инициализатора, то {whatever goes here} значит пройти {whatevergoeshere} в качестве аргумента для существующих конструкторов (если конструкторов списка инициализаторов нет, то whatever goes here передаются в качестве аргументов).

Итак, давайте упростим настройку и проигнорируем другие конструкторы, потому что, видимо, компиляторы не заботятся о них

void f(std::initializer_list<std::string> s);
void f(std::initializer_list<int> l);

За f({{}}) у нас есть это правило

В противном случае, если типом параметра является std :: initializer_list и все элементы списка инициализатора могут быть неявно преобразованы в X, последовательность неявного преобразования является худшим преобразованием, необходимым для преобразования элемента списка в X, или если Список инициализаторов не имеет элементов преобразования идентичности. Это преобразование может быть пользовательским преобразованием даже в контексте вызова конструктора списка инициализаторов.

Здесь у нас есть один элемент {} и для инициализации требуется пользовательское преобразование std::string и нет преобразования (идентичности) для int, Следовательно, int выбран.

За f({{{}}}) элемент {{}}, Может ли он быть преобразован в int? Правило

  • если список инициализаторов имеет один элемент, который сам не является списком инициализаторов, то последовательность неявного преобразования требуется для преобразования элемента в тип параметра
  • Во всех случаях, кроме перечисленных выше, преобразование невозможно.

Может ли он быть преобразован в std::string? Да, потому что у него есть конструктор списка инициализатора, который имеет std::initializer_list<char> init параметр. Следовательно, std::string выбран на этот раз.


Разница в A a3({}) в таком случае это не инициализация списка, а «нормальная» инициализация с {} аргумент (обратите внимание, что на одну вложенность меньше из-за отсутствия внешних скобок). Здесь наши двое f-функции вызываются с {}, И поскольку оба списка не имеют элементов, для обоих у нас есть преобразования идентичности и, следовательно, двусмысленность.

Компилятор в этом случае также будет учитывать f(int) и получить связь с двумя другими функциями. Но будет применяться тай-брейк, который объявляет int -параметр хуже чем initializer_list параметры. Итак, у вас есть частичный заказ {int} < {initializer_list<string>, initializer_list<int>}, что является причиной неоднозначности, так как лучшая группа последовательностей преобразования не содержит ни одного кандидата, а двух.

7

Другие решения

{} к скалярному типу (например, int, double, char*и т. д.) является преобразование личности.

{} к типу класса, кроме специализации std::initializer_list (например., std::string) является пользовательским преобразованием.

Первое превосходит второе.

7

По вопросам рекламы [email protected]