C ++ - 编译器如何在引用类型作为参数的重载函数之间做出决定?

时间:2017-12-09 23:38:24

标签: c++ c++11 implicit-conversion overloading

在学习C ++的过程中,我遇到了转换序列这个复杂的主题,我遇到了一个我自己无法解决的问题。

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(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);
}

在这两个例子中,编译器抱怨重载函数的调用&#34; g(double)&#34;很暧昧。

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);
}

但是在这个例子中,程序正确编译并打印出&#34; void g(const double&amp;&amp;)&#34;。 所以我不明白为什么编译器会抱怨前两个例子但不是第三个例子。

2 个答案:

答案 0 :(得分:3)

在重载决策中,直接引用绑定是身份转换(即使添加了限定符); 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),并且都不引用a的隐式对象参数   在没有ref-qualifier的情况下声明的非静态成员函数,S1将rvalue引用绑定到rvalue,S2绑定左值引用。
  •   

此规则允许为相同类型的rvalues和lvalues重载函数。

答案 1 :(得分:2)

重载分辨率表

此表总结了谁可以去哪里:

    ---------------------------------------------------------------------------------
               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)等更好的匹配。
  • 除非在方法等方面有诸如const之类的额外差异,否则使用上述任何一种方法重载byval版本是没有意义的。 添加一个byvalue版本:f(X x)不适用于上述的任何组合 - 在大多数情况下,它会导致任何调用的歧义,在某些情况下它会更喜欢byval版本(如果它只与[a]一起生活 - 除了左值之外的任何调用都会更喜欢byvalue版本,而左旋调用会产生歧义)。
  • 很少使用签名[d],请参阅:Do rvalue references to const have any use?