Вызывают ли пустые скобки конструктор по умолчанию или конструктор, принимающий std :: initializer_list?

Ниже приводится цитата из Эффективный Современный C ++ (стр. 55):

«Предположим, что вы используете пустой набор скобок для создания объекта, который поддерживает конструктор по умолчанию, а также поддерживает конструкцию std :: initializer_list. Что означают ваши пустые скобки? И т. Д. Правило состоит в том, что вы получаете конструкцию по умолчанию».

Я попробовал это с std :: array:

std::array<int, 10> arr{};

и получил предупреждение от g ++ (версия 4.8.2):

предупреждение: отсутствует инициализатор для члена ‘std :: array<int, 10ul> :: _ M_elems ’

что является предупреждением при попытке построить std::array из пустого std::initializer_list (увидеть Почему я могу инициализировать обычный массив из {}, но не std :: array для обсуждения этого предупреждения).

Итак, почему вышеприведенная строка кода не интерпретируется как вызов конструктора по умолчанию?

8

Решение

Это потому станд :: массив является совокупностью и, следовательно, агрегатная инициализация выполняется это покрыто проект стандарта C ++ 11 раздел 8.5.4 [Dcl.init.list] который говорит:

Инициализация списка объекта или ссылки типа T определяется следующим образом:

  • Если список инициализаторов не имеет элементов и T является типом класса с конструктором по умолчанию, объект
    значение инициализации.

  • В противном случае, если T является агрегатом, выполняется агрегатная инициализация (8.5.1).

    double ad[] = { 1, 2.0 }; // OK
    int ai[] = { 1, 2.0 }; // error: narrowing
    
    struct S2 {
    int m1;
    double m2, m3;
    };
    
    S2 s21 = { 1, 2, 3.0 }; // OK
    S2 s22 { 1.0, 2, 3 }; // error: narrowing
    S2 s23 { }; // OK: default to 0,0,0
    

и мы можем увидеть, если это не агрегат, то список можно продолжить:

  • В противном случае, если T является специализацией std :: initializer_list, объект initializer_list имеет вид
    построен как описано ниже и используется для инициализации объекта в соответствии с правилами для инициализации
    объекта из класса того же типа (8.5).
  • В противном случае, если T является типом класса, учитываются конструкторы. Применимые конструкторы перечислены
    и лучший выбирается через разрешение перегрузки (13.3, 13.3.1.7). Если сужение конверсии (см.
    ниже) требуется преобразовать любой из аргументов, программа некорректно сформирована.

Мы можем подтвердить std::array это агрегат из раздела 23.3.2.1 [Array.overview]:

Массив — это агрегат (8.5.1), который можно инициализировать с помощью
синтаксис

array<T, N> a = { initializer-list };

где initializer-list — разделенный запятыми список до N элементов
чьи типы обратимы в Т.

раздел 8.5.1 ссылка на 8.5.1 сводные показатели [Dcl.init.aggr] и говорит:

Когда агрегат инициализируется списком инициализаторов, как указано
в 8.5.4 элементы списка инициализатора принимаются как
инициализаторы для элементов совокупности, в возрастающем индексе
или заказ участника […]

и мы идем полный круг обратно в раздел 8.5.4 вот где мы начали.

8

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