Ответ 1
Все ссылки на N3797, текущий рабочий проект С++ 1y. §8.5 Инициализаторы [dcl.init]/15:
Инициализация, которая встречается в форме
T x = a;
а также при передаче аргументов, возврату функции, выдаче исключения (15.1), обработке исключения (15.3), а инициализация агрегатного члена (8.5.1) называется копированием-инициализацией. [Примечание. Копирование-инициализация может вызвать ход (12.8). -end note]
Итак, декларация:
std::atomic<int> a = 0;
выполняет инициализацию копирования. Согласно 8.5/17:
Семантика инициализаторов такова. Тип назначения - тип инициализированного объекта или ссылки, а тип источника - тип выражения инициализатора. Если инициализатор не является одним (возможно, в скобках) выражением, тип источника не определен.
Тип назначения здесь std::atomic<int>
, а тип источника - int
(т.е. decltype(0)
). Чтобы определить семантику инициализации, мы должны определить, какая из паттернов пункта 17 применяется:
- Если инициализатор представляет собой (не заключенный в скобки) бит-init-list, объект или ссылка инициализируется списком (8.5.4).
- Если тип назначения является ссылочным типом, см. 8.5.3.
- Если тип назначения - это массив символов, массив из
char16_t
, массивchar32_t
или массивwchar_t
, а инициализатор - строковый литерал, см. 8.5.2.- Если инициализатор
()
, объект инициализируется значением.- В противном случае, если тип назначения является массивом, программа плохо сформирована.
- Если тип назначения является (возможно, cv-квалифицированным) типом класса:
- Если инициализация является прямой инициализацией или если она является копией-инициализацией, где cv-неквалифицированная версия типа источника является тем же классом, что или производным классом класса назначения,... [ не применяется, тип источника
int
]- В противном случае (т.е. для остальных случаев инициализации копии) пользовательские последовательности преобразования, которые могут преобразовываться из типа источника в тип назначения или (когда функция преобразования ) к его производному классу перечислены, как описано в 13.3.1.4, и лучший выбирается с помощью разрешения перегрузки (13.3). Если преобразование невозможно или неоднозначно, инициализация плохо сформирована. Выбранная функция вызывается с выражением инициализатора в качестве аргумента; если функция является конструктором, вызов инициализирует временную версию cv-unqualified версии целевого типа. Временной является prvalue. Результат вызова (который является временный для случая конструктора) затем используется для прямой инициализации, в соответствии с вышеприведенными правилами, объект, который является местом назначения инициализации копирования. В некоторых случаях реализация разрешено исключать копирование, присущее этой прямой инициализации, путем создания промежуточный результат непосредственно в инициализированный объект; см. 12.2, 12.8.
- ...
Вот мы. Инициализационное выражение - 0
- преобразуется в std::atomic<int>
посредством создания временного объекта, инициализированного конструктором std::atomic<int>(int)
. Этот временный объект используется для прямого инициализации исходного объекта std::atomic<int>
. Другой из классов класса (возможно, cv-qualit) типа, которые мы игнорировали до сих пор, применяется:
- Если инициализация представляет собой прямую инициализацию или если она является копией-инициализацией, где рассматриваются cv-неквалифицированная версия типа источника того же класса, что и производный класс класса назначения, рассматриваются конструкторы. Соответствующие конструкторы перечислены (13.3.1.3), а лучший выбирается с помощью разрешения перегрузки (13.3). Выбранный таким образом конструктор вызывается для инициализации объекта с выражением инициализатора или списком выражений в качестве аргумента (ов). Если конструктор не применяется или разрешение перегрузки неоднозначно, инициализация плохо сформирована.
Напомним, что новый инициализатор является prvalue std::atomic<int>
. Разрешение перегрузки определяет, что не существует соответствующего конструктора std::atomic<int>
, который принимает один аргумент std::atomic<int>&&
(std::atomic<int>
не может перемещаться или копироваться) и диагностирует программу как не сформированную.
Для второй части вопроса
std::atomic<int> a = {0};
- снова инициализация копирования на 8.5/15. На этот раз, однако, применяется самая первая пуля 8.5/17:
- Если инициализатор представляет собой (не заключенный в скобки) бит-init-list, объект или ссылка инициализируется списком (8.5.4).
Для инициализации списка, мы должны посмотреть на 8.5.4/3:
Список-инициализация объекта или ссылки типа
T
определяется следующим образом:
- Если
T
является агрегатом, выполняется агрегатная инициализация (8.5.1).- В противном случае, если в списке инициализаторов нет элементов, а
T
- это тип класса с конструктором по умолчанию, объект инициализируется значением.- В противном случае, если
T
является специализациейstd::initializer_list<E>
, объект prvalueinitializer_list
строится, как описано ниже, и используется для инициализации объекта в соответствии с правилами инициализации объекта из класса того же типа (8.5).- В противном случае, если
T
- тип класса, рассматриваются конструкторы. Применяемые конструкторы перечисляются, а лучший выбирается с помощью разрешения перегрузки (13.3, 13.3.1.7). Если для преобразования любого из аргументов требуется сужение преобразования (см. Ниже), программа плохо сформирована.- ...
std::atomic<int>
- это тип класса, а не агрегированная или initializer_list
специализация, поэтому рассматриваются конструкторы. Конструктор std::atomic<int>::atomic(int)
будет выбран как идеальное совпадение и используется для инициализации объекта.