Концептуально ли инициализация списка копирования вызывает copy ctor?

До C ++ 11 мы можем выполнить инициализацию копирования, написав что-то вроде A a = 1; что более или менее эквивалентно A a = A(1);, То есть сначала создается временный объект, а затем вызывается копия ctor. Независимо от исключения копирования, это должно быть так концептуально, и копия ctor должна быть доступна.

При инициализации списка в C ++ 11 мы можем выполнить инициализацию списка копирования, написав A a = {1, 2};, На мой взгляд, это должно быть более или менее эквивалентно A a = A(1, 2);, Тем не менее, на GCC и лязг, A a = {1, 2} компилируется, даже когда ctor для копирования и перемещения недоступен (объявляется как private). Еще, A a = 1; не компилируется в GCC или clang, если соответствующий ctor копирования / перемещения недоступен. Так, A a = {1, 2}; кажется более или менее эквивалентным A a{1, 2}; которая является прямой инициализацией списка. Разница между этим и реальной прямой инициализацией списка заключается в том, что A a = {1, 2}; не компилируется, если ctor, который принимает два целых числа, является явным. В этом аспекте A a = {1, 2}; напоминает инициализацию копирования.

Итак, мой вопрос: какова точная семантика выражений типа A a = {1, 2}; концептуально? От концептуально, Эмиссия копий не мешает.

9

Решение

Стандарт описывает это довольно хорошо; [Dcl.init.list] / 3:

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

  • […]
  • В противном случае, если T является типом класса, конструкторы рассматриваются.
    перечислены соответствующие конструкторы и выбран лучший
    через разрешение перегрузки (13.3, 13.3.1.7). Если сужение
    преобразование (см. ниже) требуется для преобразования любого из аргументов,
    программа плохо сформирована.
[over.match.list] (выделено мной):

Когда объекты неагрегированного класса T инициализируются списком
(8.5.4), разрешение перегрузки выбирает конструктор в два этапа:

  • Первоначально функции-кандидаты являются конструкторами списка инициализаторов (8.5.4) класса T и список аргументов состоит из
    список инициализаторов как один аргумент.

  • Если жизнеспособный конструктор списка инициализаторов не найден, Разрешение перегрузки выполняется снова, где все функции-кандидаты
    конструкторы класса T и список аргументов состоит из
    элементы списка инициализатора.

Если список инициализатора не имеет
элементы и T имеет конструктор по умолчанию, первая фаза опущена.
В инициализации копирования списка, если explicit конструктор выбран,
инициализация плохо сформирована.

Следовательно, если конструктор списка инициализаторов не найден (как в вашем случае), элементы списка инициализаторов составляют аргументы для вызова конструктора.
На самом деле, только Разница между прямой инициализацией списка и инициализацией копирования списка заключена в последнем, выделенном жирным шрифтом предложении.

Это одно из преимуществ инициализации списка: это не требует наличия специальной функции-члена, которая в любом случае не будет использоваться.

9

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


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