Разрешение перегрузки, когда аргумент является списком инициализаторов, а параметр является ссылкой

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

person stackcpp    schedule 12.10.2015    source источник
comment
Инициализация списка определена в [decl.init.list] и не упоминается как выражение аргумента (что имеет смысл, поскольку это не выражение). Кроме того, bind напрямую подразумевает, что типы известны. Инициализатор в фигурных скобках не имеет типа.   -  person 0x499602D2    schedule 12.10.2015
comment
@ 0x499602D2 Какое правило применяется, когда аргумент является списком инициализаторов в 13.3.3.1.4 [over.ics.ref]? И первое, и второе применяются к выражению аргумента, и они используют связывание непосредственно для различения.   -  person stackcpp    schedule 13.10.2015
comment
См. В противном случае, если T является ссылочным типом... Это это правило, которое охватывает инициализацию ссылки из списка инициализаторов.   -  person 0x499602D2    schedule 13.10.2015
comment
OTOH, правило, на которое я ссылался выше ([dcl.init.list]/3.8), говорит, что создается временный объект, и ссылка привязывается к этому временному файлу; так что это временное может быть выражением аргумента, на которое ссылается [over.ics.ref].   -  person 0x499602D2    schedule 13.10.2015
comment
@ 0x499602D2 Вы можете ответить на этот вопрос, я приму его.   -  person stackcpp    schedule 13.10.2015
comment
Я не думаю, что мои комментарии правильно ответили на вопрос. Может быть, кто-то еще придет.   -  person 0x499602D2    schedule 13.10.2015


Ответы (1)


У нас просто есть дефект, о котором сообщалось как http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1536 (я только что обнаружил это, не знал об этом отчете ранее, когда писал другой ответ).

Мне кажется проблематичной интерпретация того, что over.ics.ref полностью не зависит от списка инициализаторов и говорит о привязке созданных временных файлов (тот, который создан decl.init.list) к ссылке. В частности, в over.ics.list сказано, что over.ics.ref будет делегировать over.ics.list для инициации временки, указывая, что over.ics.ref активен уже до создания временки (также есть случаи в decl.init.list, где временные файлы не создаются). Кроме того, преобразование { } в ClassType& должно быть определяемым пользователем преобразованием, но временное значение rvalue будет напрямую привязано к ссылке при рассмотрении преобразования, изолированного от аргумента списка инициализатора.

person Johannes Schaub - litb    schedule 13.10.2015