当参数是初始化列表且参数是引用时的重载解析

Overload resolution when an argument is an initializer list and the parameter is a reference

struct A { A(int);};
struct B { explicit B(A); B(const B&);};
B b({0}); 

我问了一个问题 和@Johannes Schaub - litb 解释了有效的规则。但我对 13.3.3.1.4 引用绑定.

仍有一些疑问

N4527 13.3.3.1.5 [over.ics.list] p1 和 p8

1 When an argument is an initializer list (8.5.4), it is not an expression and special rules apply for converting it to a parameter type.

8 Otherwise, if the parameter is a reference, see 13.3.3.1.4.

13.3.3.1.4 [over.ics.ref] p1 和 p2

1 When a parameter of reference type binds directly (8.5.3) to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion (13.3.3.1). [ Example... ]

If the parameter binds directly to the result of applying a conversion function to the argument expression, the implicit conversion sequence is a user-defined conversion sequence (13.3.3.1.2), with the second standard conversion sequence either an identity conversion or, if the conversion function returns an entity of a type that is a derived class of the parameter type, a derived-to-base Conversion.

2 When a parameter of reference type is not bound directly to an argument expression, the conversion sequence is the one required to convert the argument expression to the underlying type of the reference according to 13.3.3.1. Conceptually, this conversion sequence corresponds to copy-initializing a temporary of the underlying type with the argument expression. Any difference in top-level cv-qualification is subsumed by the initialization itself and does not constitute a conversion.

问题1:"argument expression"是否包括"initializer list"?请参阅上面的 13.3.3.1.5 [over.ics.list] p1 粗体短语和

1.3.2 [defns.argument]

argument

<function call expression> expression in the comma-separated list bounded by the parentheses (5.2.2)



8.5 [dcl.init]p17

17 The semantics of initializers are as follows. The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression. If the initializer is not a single (possibly parenthesized) expression, the source type is not defined.

(17.1) — If the initializer is a (non-parenthesized) braced-init-list, the object or reference is list-initialized (8.5.4).

(17.2) — If the destination type is a reference type, see 8.5.3.

8.5.3 [dcl.init.ref] p5

A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:

[...]

(5.2.2.2) — Otherwise, a temporary of type “cv1 T1” is created and copy-initialized (8.5) from the initializer expression. The reference is then bound to the temporary.

[...]

在除最后一种情况外的所有情况下(即从初始化表达式创建和初始化临时对象), 据说引用直接绑定到初始化表达式。

问题2:"bind directly"是否包括初始化器为初始化器列表的情况?换句话说,当初始化器是一个初始化器列表时,我们可以使用"bind directly"吗?

注意:"bind directly" 是 8.5.3 中的定义,被 8.5 p17.1 引用,"initializer is a braced-init-list" 是 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],但我可以' 看到任何关于参数的词,它是一个初始化列表。我认为 "bind directly" 和 "argument" 的定义与 "initializer list" 无关。

当参数是初始化列表并且参数是引用时,你能解释一下重载决议是如何工作的吗?

注意:这三个问题 相关。当您回答第三个问题时,您将回答第一和第二个问题。

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

我们只是有一个缺陷,报告为 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& 应该是用户定义的转换,但是在考虑与初始化列表参数隔离的转换时,临时右值将直接由引用绑定。