struct A { A(int);};
struct B { explicit B(A); B(const B&);};
B b({0});
Я задал вопрос Разрешение перегрузки дает разные результаты между gcc и clang и @Johannes Schaub - litb объяснили действующие правила. Но у меня остались вопросы по 13.3.3.1.4 привязке ссылок.
N4527 13.3.3.1.5 [over.ics.list] p1 и p8
1 Если аргумент является списком инициализаторов (8.5.4), это не выражение, и для его преобразования в тип параметра применяются специальные правила.
8 В противном случае, если параметр является ссылкой, см. 13.3.3.1.4.
13.3.3.1.4 [over.ics.ref] p1 и p2
1 Когда параметр ссылочного типа связывается напрямую (8.5.3) с выражением-аргументом, последовательность неявного преобразования является преобразованием идентичности, если только выражение-аргумент не имеет типа, является производным классом типа параметра, и в этом случае последовательность неявного преобразования является преобразованием производного в базовое (13.3.3.1). [ Пример... ]
Если параметр привязывается непосредственно к результату применения функции преобразования к выражению аргумента, неявная последовательность преобразования представляет собой определяемую пользователем последовательность преобразования (13.3.3.1.2), а вторая стандартная последовательность преобразования представляет собой преобразование идентичности или, если функция преобразования возвращает объект типа, который является производным классом типа параметра, преобразованием производного в базовый.
2 Когда параметр ссылочного типа не связан напрямую с выражением-аргументом, последовательность преобразования требуется для преобразования выражения-аргумента в базовый тип ссылки в соответствии с к 13.3.3.1. Концептуально эта последовательность преобразования соответствует копированию-инициализации временного объекта базового типа с выражением аргумента. Любая разница в cv-квалификации верхнего уровня учитывается самой инициализацией и не представляет собой преобразование.
Вопрос 1. Включает ли «выражение аргумента» «список инициализаторов»? См. 13.3.3.1.5 [over.ics.list] p1 полужирная фраза выше и
1.3.2 [аргумент определения]
аргумент
‹выражение вызова функции> выражение в списке, разделенном запятыми, заключенном в круглые скобки (5.2.2)
8.5 [dcl.init] стр. 17
17 Семантика инициализаторов следующая. Целевой тип — это тип инициализируемого объекта или ссылки, а исходный тип — это тип выражения инициализатора. Если инициализатор не является одиночным (возможно, заключенным в скобки) выражением, исходный тип не определен.
(17.1) — Если инициализатором является (не заключенный в скобки) список инициализации в фигурных скобках, объект или ссылка инициализируется списком (8.5.4).
(17.2) — Если тип назначения является ссылочным типом, см. 8.5.3.
8.5.3 [dcl.init.ref] p5
Ссылка на тип «cv1 T1» инициализируется выражением типа «cv2 T2» следующим образом:
[...]
(5.2.2.2) — В противном случае создается временный объект типа «cv1 T1» и инициализируется копированием (8.5) из выражения инициализатора. Затем ссылка привязывается к временному.
[...]
Во всех случаях, кроме последнего (т. е. создания и инициализации временного объекта из выражения инициализатора), считается, что ссылка связывается напрямую с выражением инициализатора.
Вопрос 2. Включает ли "связывание напрямую" случай, когда инициализатором является список инициализаторов? Другими словами, можем ли мы использовать «связать напрямую», когда инициализатором является список инициализаторов?
ПРИМЕЧАНИЕ. «Связать напрямую» — это определение в 8.5.3, которое цитируется в 8.5 p17.1, а «инициализатор — это список-инициализация в фигурных скобках» — это определение в 8.5.4, которое цитируется в 8.5 p17.2.
//case 5.2.1.2
struct X{};
struct Y{Y(X);};
const Y& y1 = X(); // bind directly
const Y& y2 = {X()}; // bind directly or not?
struct Z{operator X();};
const X& x1 = Z(); // bind directly
const X& x2 = {Z()}; // bind directly or not?
//case 5.2.2.1
struct A{operator int();};
const int& a1 = A(); // bind directly
const int& a2 = {A()}; // bind directly or not?
struct B{B(int);};
const B& b1 = 1; // bind directly
const B& b2 = {1}; // bind directly or not?
//csse 5.2.2.2
int i3 = 2;
double&& rrd3 = i3; // not bind directly
struct A { A(int);};
struct B { explicit B(A); B(const B&);};
B b({0}); // when overload resolution choose B(const B&) as a candidate,
// {0} -> constB& bind directly or not?
Вопрос 3 (основной вопрос):
когда аргумент является списком инициализаторов, а параметр является ссылкой, 13.3.3.1.5 [over.ics.list] p8 цитирует 13.3.3.1.4 [over.ics.ref], но я не вижу никаких слов about аргумент, который является списком инициализаторов. Я думаю, что определение «привязать напрямую» и «аргумент» не связано со «списком инициализаторов».
Можете ли вы объяснить, как работает разрешение перегрузки, когда аргумент является списком инициализаторов, а параметр является ссылкой?
ПРИМЕЧАНИЕ. Эти три вопроса связаны. Когда вы ответите на третий вопрос, вы ответите на первый и второй.
struct A { A(int);};
struct B { explicit B(A); B(const B&);};
B b1(0); //when overload resolution choose B(const B&) as a candidate,
//0 -> const B& binds directly
//13.3.3.1.4 [over.ics.ref] p1 "If the parameter binds directly..."
A a;
B b2(a) //when overload resolution choose B(const B&) as a candidate,
//a -> const B& binds directly
//13.3.3.1.4 [over.ics.ref] p1 "If the parameter binds directly..."
B b3({0})//when overload resolution choose B(const B&) as a candidate,
//{0} -> const B& binds directly or not?
//if it is not bound directly, 13.3.3.1.4 [over.ics.ref] p2
B b3({a})//when overload resolution choose B(const B&) as a candidate,
//{a} -> const B& binds directly or not?
//if it is not bound directly, 13.3.3.1.4 [over.ics.ref] p2
T
является ссылочным типом... Это это правило, которое охватывает инициализацию ссылки из списка инициализаторов. - person 0x499602D2   schedule 13.10.2015