重载引用与const引用

时间:2014-06-04 04:46:05

标签: c++ pass-by-reference

我有以下代码:

#include <iostream>

template <typename T>
void f(T& x)        
{
    std::cout << "f(T& )" << std::endl; 
}

template <typename T>
void f(const T& x) 
{ 
    std::cout << "f(const T& )" << std::endl; 
}

int main() 
{
    int a = 0;
    const float b = 1.1;

    f(a); // call f(T&)
    f(b); // call f(const T&)
}

输出结果为:

f(T& )
f(const T& )

我的问题是:编译器如何知道要调用哪个函数?如果我从函数定义中删除引用,那么我会得到一个“模糊调用”类型的错误,即error: redefinition of 'f'。对我来说,看起来f(T&)同样可以用于两个调用,为什么const版本明确要求f(b)

2 个答案:

答案 0 :(得分:9)

鉴于两个竞争的重载,标准要求编译器选择具有“最佳匹配”的重载。 (如果没有唯一的最佳过载,或者如果无法访问唯一的最佳过载,则程序格式不正确。)

在这种情况下,规则由§13.3.3.2[over.ics.rank] / p3提供:

  

标准转换序列S1是比标准转换序列S2更好的转换序列,如果:

     
      
  • [...]

  •   
  • S1和S2是引用绑定(8.5.3),引用引用的类型除了顶级cv限定符之外是相同的类型,并且S2引用的引用引用的类型是比由S1初始化的引用所引用的类型更符合cv。

  •   

这是标准中给出的例子:

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

在您的情况下,const T&T&更符合资格,因此根据标准,f(T&)f(const T&)更合适并且通过重载决策选择

答案 1 :(得分:6)

  1. f(T&)f(T const&)
    这两个函数是不同的,因为第一个签名表明通过引用传递的任何变量都可以被函数修改。因此const float不能传递给第一个函数,第二个函数是编译器唯一可行的选择。 nonconst变量可以传递给两者,因此编译器必须选择更合适的变量(如果有的话)。标准说,为了调用第二个函数,编译器必须向任何nonconst变量添加const,而对于第一个函数,这不是必需的。添加const是一种隐式转换,它更糟糕&#34; converison(读作 more 转换步骤)比不添加任何内容。因此,标准要求编译器在传递非对象变量时选择第一个函数 如果您想知道:文字和临时文件不能绑定到非对象引用,那么f(4)f("meow")f(someFunc())都会调用第二个函数。

  2. f(T)f(const T)
    它们看起来不同,但在重载分辨率或功能签名方面却没有。它们都是按值调用,或者是编译器:将参数的副本传递给函数。唯一的区别在于函数定义,您需要变量在函数体中保持不变。任何函数声明都不会影响函数定义签名中的变量定义:

    void f(int);          //a declaration
    void f(int i);        //redeclaration of the same function
    void f(int const);    //still the same function redeclared
    void f(int const i2); //yes... a redeclaration
    
    void f(int const i) { //at last a function definition and the copy of the argument used in the function body is required to be const
      //...
    } 
    
    void f(int i) {       //there is only one f, so this is a redefinition!
      //...
    }  
    

    这不是&#34; ambuguos调用类型错误&#34;,因为编译器只有一个函数而且没有歧义。错误只是你确实两次确定相同的功能。因此,在许多样式指南中,首选函数声明没有顶级const,编译器通常会忽略它们,而不会在错误或警告消息中提及它们。