我正在尝试了解重载解析。
首先让我们考虑第一种情况:
struct int1{
int val;
operator int&()&{
return val;
}
operator const int &() const&{
return val;
}
};
void f(int &){} //f#1
void f(const int&){} //f#2
void test1(){
int1 x;
f(x);
//Conversion sequence for f#1:
// - int_wrapper& --> int1::operator int&
// => Ranking: user defined conversion rank
//Converison sequence for f#2:
// - int1& --> int1::operator int & --> const int&
// - int1& --> const int1 & --> int1::operator const int&
// => Ranking: ambiguous because 2 conversion sequence [over.best.ics]/10
// => user defined conversion rank
//
//=> No best viable overload, 2 user defined conversion rank
}
与我的错误分析不同,编译器同意:对f
的调用不明确。为什么呢?
现在考虑第二种情况,这非常相似,我只是将int&
替换为int &&
:
struct int2{
int val;
operator int&&()&&{
return std::move(val);
}
operator const int &() const&{
return val;
}
};
void g(int &&){} // g#1
void g(const int&){} // g#2
void test2(){
int2 x;
g(std::move(x));
//Conversions sequence for g#1
// - int2&& --> int2::operator int&&
// => Ranking: user defined conversion rank
//Conversion sequence for g#2
// - int2&& --> const int2& --> int2::operator const int&
// - int2&& --> int2::operator int&& --> const int&
// => Ranking: ambiguous because 2 conversion sequence [over.best.ics]/10
// => user defined conversion rank
//
//=> No best viable overload, 2 user defined conversion rank
}
我的分析(在这种情况下肯定是错误的)也得出类似结论,对g
的调用是模棱两可的。不幸的是,在第二种情况下,编译器不同意:
g
含糊不清; g
不含糊。什么是正确的分析,哪个编译器是对的?
您能否确定以下规则不适用的原因,或何时适用?
[over.best.ics] / 10:
如果存在几个不同的转换序列,每个转换序列都将参数转换为参数类型,那么 与参数相关联的隐式转换序列被定义为唯一转换序列 指定了 模糊转换序列 。为了将隐式转换序列排序为 在16.3.3.2中描述的,模糊转换序列被视为用户定义的转换序列 与任何其他用户定义的转换序列无法区分
答案 0 :(得分:3)
这两个例子都是更简单的基本概念的更复杂的表示:
int&
对于第一个电话,我们支持here.,因此int const&
优于int&&
。对于第二个调用,我们赞成less cv-qualified type过度绑定到左值引用,因此int const&
优于int1&
。
在特定示例中,这些首选项表现为通过隐式对象参数使用的转换函数的选择。对于第一个示例,因为我们将隐式对象参数绑定到int&
以转换为int1 const&
,但int const&
转换为int2&&
。同样,在第二个示例中,我们将隐式对象参数绑定到int&&
以转换为int2 const&
,但int const&
转换为{{1}}。
我称之为铿锵声。
答案 1 :(得分:1)
N4713 16.3.3.2:
3.3 用户定义的转换序列U1是一个更好的转换序列,如果它们包含相同的用户定义转换函数或构造函数,或者它们在聚合初始化中初始化同一个类,则它是另一个用户定义的转换序列U2在任何一种情况下,U1的第二个标准转换序列优于U2的第二个标准转换序列。 [实施例
struct A {
operator short();
} a;
int f(int);
int f(float);
int i = f(a); // calls f(int), because short→int is // better than short →float
结束例子]
因此,标准转化是关键:
<强> 3.2 强> 标准转换序列S1是比标准转换序列S2更好的转换序列,如果
<强> 3.2.3 强> S1和S2是引用绑定(11.6.3),并且都不引用没有ref-qualifier声明的非静态成员函数的隐式对象参数,S1将rvalue引用绑定到rvalue,S2绑定左值引用[示例:
int i;
int f1();
int&& f2();
int g(const int&);
int g(const int&&);
int j = g(i); // calls g(const int&)
int k = g(f1()); // calls g(const int&&)
int l = g(f2()); // calls g(const int&&)
struct A {
A& operator<<(int);
void p() &;
void p() &&;
};
A& operator<<(A&&, char);
A() << 1; // calls A::operator<<(int)
A() << ’c’; // calls operator<<(A&&, char)
A a;
a << 1; // calls A::operator<<(int)
a << ’c’; // calls A::operator<<(int)
A().p(); // calls A::p()&&
a.p(); // calls A::p()&
结束例子]
<强> 3.2.6 强>: S1和S2是引用绑定(11.6.3),引用引用的类型除了顶级cv限定符之外是相同的类型,并且S2引用的引用引用的类型比cv更合格。由S1初始化的引用所引用的类型。 [例如:
int f(const int &);
int f(int &);
int g(const int &);
int g(int);
int i;
int j = f(i); // calls f(int &)
int k = g(i); // ambiguous
struct X {
void f() const;
void f();
};
void g(const X& a, X b) {
a.f(); // calls X::f() const
b.f(); // calls X::f()
}
- 结束示例]
所以gcc
符合标准的要求。