Jan*_*šil 2 c++ language-lawyer overload-resolution implicit-conversion reference-binding
在以下程序中,应选择哪个(如果有)转换功能,为什么?
int r;
struct B {};
struct D : B {};
struct S {
D d;
operator D&(){r=1; return d;} // #1
operator B&(){r=2; return d;} // #2
};
int main() {
S s;
B& b = s;
return r;
}
Run Code Online (Sandbox Code Playgroud)
gcc和clang选择均选择转换功能#2。但为什么?
标准说:
(1)在[dcl.init.ref]中指定的条件下,可以将引用直接绑定到将转换函数应用于初始化程序表达式的结果。重载解析用于选择要调用的转换函数。假设“对cv1 T的引用”是要初始化的引用的类型,而“ cv S”是初始化程序表达式的类型,其中S为类类型,则按以下方式选择候选函数:
(1.1)-考虑S的转换函数及其基类。那些未隐藏在S中且产生类型“对cv2 T2的左值引用”(初始化对函数的左值引用或右值引用时)或“ cv2 T2”或“对cv2 T2的右值引用”的非显式转换函数将右值引用或左值引用初始化为函数),其中“ cv1 T”与“ cv2 T2”的引用兼容)是候选函数。对于直接初始化,未隐藏在S中的那些显式转换函数会产生类型“对cv2 T2的左值引用”(初始化对函数的左值引用或右值引用)或“对cv2 T2的右值引用”(当初始化对函数的右值引用或左值引用),
(2)参数列表有一个参数,它是初始化器表达式。[?注:此参数将与转换函数的隐式对象参数进行比较。-?尾注?]
这里我们有两个候选函数#1和#2。两者都可行-如果删除其中之一,程序仍会编译。这两个转换函数仅采用隐式参数,并且具有相同的cv和ref限定。因此,没有一个应该是最可行的,并且该程序也不应编译。为什么编译?
好了,如您所知,重载解决方案分为三个阶段:(1)枚举候选函数;(2)确定哪些候选功能可行;(3)选择最佳可行功能。
根据[over.match.best] / 1:
... 如果对于所有参数i,ICS i()的转换顺序都不比ICS i()差,则将一个可行函数
F1定义为比另一个可行函数更好的函数,然后F2F1F1
- 对于某些参数j,ICS j(
F1)比ICS j(F2)更好的转换顺序,或者,如果不是,- 上下文是通过用户定义的转换进行初始化(请参见11.6、16.3.1.5和16.3.1.6),并且从返回类型
F1到目标类型(即,正在初始化的实体的类型)的标准转换顺序是从返回类型F2到目标类型[example ...] 的标准转换序列比标准转换序列更好;如果不是,- [...更多决胜局规则...]
从s#1或#2到隐式对象参数的隐式转换是身份转换,因此ICS1(#1)和ICS2(#1)不可区分,第二个要点与此相关。在#1的情况下,需要从基数转换为从转换函数的返回类型(即)转换D&为所需的类型(即)B&。在#2的情况下,标准转换顺序是身份转换(B&to B&),效果更好。因此,在这种情况下,选择功能#2优于#1。
| 归档时间: |
|
| 查看次数: |
82 次 |
| 最近记录: |