当实参是初始化列表而形参是引用时,重载解析
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});
我问了一个问题,重载解析在gcc和clang之间得到不同的结果,@Johannes Schaub - litb解释了激活的规则。但是我对13.3.3.1.4引用绑定还有一些疑问。
N4527 13.3.3.1.5 [over.ics.]
当实参是初始化列表(8.5.4)时,不是表达式,并且应用特殊规则进行转换8否则,如果是引用,请参见13.3.3.1.4。
13.3.3.1.4 [over.ics。Ref] p
当引用类型的形参直接将(8.5.3)绑定到实参表达式时,进行隐式转换类的派生类的类型除外,否则参数表达式为恒等转换在这种情况下,隐式转换序列是派生到基的转换(13.3.3.1)。(例子…)如果形参直接绑定到对对象应用转换函数的结果参数表达式时,隐式转换序列为用户定义的转换序列(13.3.3.1.2);对于第二个标准转换序列,要么是单位转换,要么是转换函数返回类型为参数类型的派生类的实体,即派生到基的转换。
2当引用类型的形参没有直接绑定到实参表达式时,转换顺序是否需要将参数表达式转换为引用的基础类型13.3.3.1。从概念上讲,此转换序列对应于复制初始化类的临时对象使用参数表达式的基础类型。顶级简历资格的任何差异都包含在初始化本身,不构成转换。
问题1:"参数表达式"是否包含"初始化列表"?参见13.3.3.1.5 [over.ics]。
1.3.2 [defns.argument]
论证<函数调用表达式>表达式在以逗号分隔的圆括号括起的列表中(5.2.2)函数调用表达式>
(dcl
8.5。init) p17
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:"直接绑定"是否包括初始化项是初始化项列表的情况?换句话说,当初始化项是初始化项列表时,我们可以直接使用"bind"吗?
注意:"bind direct "是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]。参考13.3.3.1.4 [over.ics.]ref],但是我没有看到任何关于argument的文字,它是一个初始化列表。我认为"直接绑定"answers"参数"的定义与"初始化列表"无关。
你能解释一下当实参是初始化列表而形参是引用时,重载解析是如何工作的吗?
注意:这三个问题与相关。当你回答第三个问题时,你将回答第一个和第二个问题。
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与初始化列表完全无关,并且谈论的是绑定到引用的已创建的临时(由decle .init.list创建的)的解释对我来说似乎有问题。特别是,over.ics.list表示over.ics.ref将委托给over.ics.list来初始化临时对象,这表明over.ics.ref在创建临时对象之前已经处于活动状态(也有在decle .init.list中没有创建临时对象的情况)。此外,{ }
到ClassType&
应该是一个用户定义的转换,但是当考虑与初始化列表参数隔离的转换时,临时右值将直接由引用绑定。
- 取消引用运算符不能重载
- 错误:无法解析对重载函数的引用;你的意思是调用它吗?
- 传递空初始值设定项列表时使用右值和左值引用候选项的重载解析
- 为什么我的运算符 + 重载尽管是通过引用传递的,但仍调用我的复制构造函数?
- C++编程:运算符重载中的引用如何工作?
- 重载运算符*以获取对另一个类的实例的引用
- 对运算符=使用通用引用,而不是多个重载
- 如何重载下标运算符 [] 以引用 2d STL 数组?
- 具有参数包和通用引用的重载选择
- 当有右值构造函数可用时,为什么从右值调用类引用构造函数重载?
- C++:对函子重载调用运算符的未定义引用
- 运算符重载C++类中的引用返回
- 错误:无法解析对重载函数的引用
- 两个相同的重载运算符[]一个返回引用
- 在函数重载中将右值引用实现为参数
- 模板流运算符重载错误:引用初始化无效,与basic_istream和basic_ifstream之间的差异有关
- 运算符重载C++引用或值
- C++类模板构造函数 -- 重载引用 (U&) 与数组 (U*) 失败
- C++ 类运算符重载引用
- 重载引用与const引用