#include <iostream>
struct A{
A(int){
}
};
struct B{
B() = default;
B(A){
}
B(B const&){}
B(B&&){}
};
int main(){
B b({0});
}
Для данных кодов возможными функциями являются:
#1 B::B(A)
#2 B::B(const B&)
#3 B::B(B&&)
В соответствии со стандартом, для # 1 объект типа A инициализируется в виде списка копирования {0} как A a = {0}
, A::A(int)
рассматривается для инициализации, поэтому только стандартное преобразование в # 1. Для # 2 это инициализация ссылочной формы braced-init-list
, которая является причиной [dcl.init.list]
В противном случае, если T является ссылочным типом, тип значения, на который ссылается T, генерируется. Значение prvalue инициализирует свой объект результата путем инициализации copy-list-initialization или direct-list-initialization, в зависимости от вида инициализации для ссылки. Затем значение prvalue используется для прямой инициализации ссылки. [Примечание: Как обычно, привязка завершится неудачно, и программа будет некорректной, если ссылочный тип является lvalue-ссылкой на неконстантный тип. - примечание конца]
Таким образом, оно приравнивается к const B& = {0}
, в этой инициализации функция преобразования равна B::B(A)
, а аргумент равен 0
, поэтому B tmp = {0}
и 'B :: B (A) 'считается, что параметр инициализируется аргументом 0
, как A parameter = 0
.
В противном случае (т. Е. Для остальных случаев инициализации копирования), определяется пользователем последовательности преобразования, которые могут преобразовывать тип источника в тип назначения или (если используется функция преобразования) в его производный класс, перечисляются, как описано в [over.match.copy], и лучший из них выбирается с помощью перегрузки. разрешение ...
Таким образом, в # 2 существует пользовательское преобразование, и ситуация # 3 такая же, как в # 2, и соответствует [over.ics.rank ] ,
стандартная последовательность преобразования является лучшей последовательностью преобразования, чем определяемая пользователем последовательность преобразования или последовательность преобразования многоточия, и ...
стандартное преобразование лучше чем определяемое пользователем преобразование, поэтому # 1 должно быть лучше, чем # 2 и # 3, но на самом деле, g ++ сообщает, что вызов неоднозначен, почему? Сообщение об ошибке:
main.cpp: In function ‘int main()’:
main.cpp:12:10: error: call of overloaded ‘B(<brace-enclosed initializer list>)’ is ambiguous
B b({0});
^
main.cpp:8:3: note: candidate: B::B(A)
B(A){
^
main.cpp:6:8: note: candidate: constexpr B::B(const B&)
struct B{
^
main.cpp:6:8: note: candidate: constexpr B::B(B&&)