Ответ 1
Это языковая причуда. Первый f
соответствует лучше, потому что ваш A
не требует преобразования в соответствии с типом аргумента (A
), но когда компилятор пытается сделать вызов фактом, что подходящий конструктор копирования не найден, приводит к сбою вызова, Язык не позволяет учитывать возможность фактического вызова при выполнении этапа разрешения перегрузки.
Ближайшая стандартная цитата ISO/IEC 14882: 2011 13.3.3.1.2 Пользовательские последовательности преобразования [over.ics.user]:
Преобразование выражения типа класса в один и тот же тип класса дано в виде Точного совпадения, а преобразование выражения типа класса к базовому классу этого типа присваивается ранг конверсии, несмотря на то, что в этих случаях вызывается конструктор копирования/перемещения (т.е. пользовательская функция преобразования).
Для случая инициализации списка вам, вероятно, нужно посмотреть: 13.3.3.1.2 Пользовательские последовательности преобразования [over.ics.user]
Когда объекты неагрегатного типа типа T инициализируются списком (8.5.4), разрешение перегрузки выбирает конструктор в две фазы:
- Изначально функции-кандидаты - это конструкторы-инициализаторы-списки (8.5.4) класса T и Список аргументов состоит из списка инициализаторов как один аргумент.
- Если не найден жизнеспособный конструктор списка инициализаторов, снова выполняется разрешение перегрузки, где Функции-кандидаты - все конструкторы класса T, а список аргументов состоит из элементов списка инициализаторов.
Поскольку разрешение перегрузки должно смотреть на жизнеспособных конструкторов в каждом случае для f(A)
и f(B)
, оно должно отклонить последовательность, пытающуюся привязать A()
к A(A&)
, но B(const A&)
по-прежнему жизнеспособна.