C++;-编译器如何在以引用类型作为参数的重载函数之间做出决定? 在学习C++的时候,我遇到了复杂的转换序列,我遇到了一个我自己无法解决的问题。p> void g(const double) { std::cout << "void g(const double)" << std::endl; } void g(const double&&) { std::cout << "void g(const double&&)" << std::endl; } int main(int argc, char **argv) { g(3.14); return (0); } void g(常数双精度) { std::cout
在重载解析中,直接引用绑定是一种身份转换(即使添加了限定符);对于C++;-编译器如何在以引用类型作为参数的重载函数之间做出决定? 在学习C++的时候,我遇到了复杂的转换序列,我遇到了一个我自己无法解决的问题。p> void g(const double) { std::cout << "void g(const double)" << std::endl; } void g(const double&&) { std::cout << "void g(const double&&)" << std::endl; } int main(int argc, char **argv) { g(3.14); return (0); } void g(常数双精度) { std::cout,c++,c++11,implicit-conversion,overloading,C++,C++11,Implicit Conversion,Overloading,在重载解析中,直接引用绑定是一种身份转换(即使添加了限定符);对于double来说,匹配double的参数或对-double的引用并没有好坏之分 在您的示例中,const有点像是在转移注意力。对于非引用类型,f(const double),顶级const不是函数签名的一部分;在f(const double&)中,它仍然是直接绑定,因此仍然是身份转换 所以,前两种情况都是身份转换,没有理由选择其中一种 在案例3中,规则C++14[over.ics.rank]/3.1.3适用: 标准转换序列S1是比
double
来说,匹配double
的参数或对-double
的引用并没有好坏之分
在您的示例中,const
有点像是在转移注意力。对于非引用类型,f(const double)
,顶级const
不是函数签名的一部分;在f(const double&)
中,它仍然是直接绑定,因此仍然是身份转换
所以,前两种情况都是身份转换,没有理由选择其中一种
在案例3中,规则C++14[over.ics.rank]/3.1.3适用:
标准转换序列S1是比标准转换序列更好的转换序列
S2如果
- [……]
- S1和S2是引用绑定(8.5.3),都没有引用 声明的非静态成员函数没有ref限定符,S1将右值引用绑定到右值,S2绑定左值引用
---------------------------------------------------------------------------------
Caller | lvalue | const lvalue | rvalue | const rvalue
Function | | | |
---------------------------------------------------------------------------------
[a] f(X& x) | V (1) | | |
---------------------------------------------------------------------------------
[b] f(const X& x) | V (2) | V | V (3) | V (2)
---------------------------------------------------------------------------------
[c] f(X&& x) | | | V (1) |
---------------------------------------------------------------------------------
[d] f(const X&& x) | | | V (2) | V (1)
---------------------------------------------------------------------------------
- 以上所有签名可以共存
- V符号标记可能的有效分辨率
- 当同一呼叫者有多个有效的解析时,它们被编号,(1)比(2)更匹配,以此类推
- 使用上述任何一种重载byval版本都没有意义,除非有额外的区别,比如方法上的const等。 添加byvalue版本:f(X X)不能很好地与上述任何组合一起工作-在大多数情况下,它会导致任何调用的歧义,在某些情况下,它只会更喜欢byval版本(如果它仅与[a]共存-除左值外的任何调用都会更喜欢byvalue版本,而左值调用会导致歧义)
- 签名[d]很少使用,请参见:
void g(const double)
与void g(double)
在重载解决方面是相同的?我不完全确定,但我认为void g(const double&)
与void g(double&)是相同的
too\。类似3.14的文字。在重载上下文中,将右值作为右值引用传递比将右值作为常量引用传递更可取。将右值作为常量引用传递被认为是“更糟糕的”而不是作为右值引用、值引用或常量引用进行传递。但是,按值传递、作为右值引用或常量引用在首选项方面被认为是“相等”的,因此具有歧义性。这是简短的胶囊摘要版本。@RSahu后两者不相同(其中只有一个可以接受类型为constdouble
)的xvalue@M.M,感谢您的澄清。原则上,一旦您有一个函数按值接收一个对象,请说void f(T)
,并且您决定重载f
,以便能够通过引用获取该对象,请说void f(T&)
-您将为重载解析过程中出现的歧义创建空间。您通常希望避免此类API。您通常希望基于右值和(常量)左值引用重载,或者只传递值,但不能同时传递两者。
void g(const double&&)
{
std::cout << "void g(const double&&)" << std::endl;
}
void g(const double&)
{
std::cout << "void g(const double&)" << std::endl;
}
int main(int argc, char **argv)
{
g(3.14);
return (0);
}
---------------------------------------------------------------------------------
Caller | lvalue | const lvalue | rvalue | const rvalue
Function | | | |
---------------------------------------------------------------------------------
[a] f(X& x) | V (1) | | |
---------------------------------------------------------------------------------
[b] f(const X& x) | V (2) | V | V (3) | V (2)
---------------------------------------------------------------------------------
[c] f(X&& x) | | | V (1) |
---------------------------------------------------------------------------------
[d] f(const X&& x) | | | V (2) | V (1)
---------------------------------------------------------------------------------