重载引用与const引用

vso*_*tco 9 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&)
}
Run Code Online (Sandbox Code Playgroud)

输出是:

f(T& )
f(const T& )
Run Code Online (Sandbox Code Playgroud)

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

T.C*_*.C. 9

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

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

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

  • [...]

  • S1和S2是引用绑定(8.5.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
Run Code Online (Sandbox Code Playgroud)

在你的情况下,const T&更符合cv T&标准,因此通过标准,f(T&)更适合f(const T&)并且通过重载分辨率选择.

  • @vsoftco真的没有`const`传递值.在函数签名中忽略顶级`consts`.所以`void foo(T t);`与`void foo(const T t);`的功能相同. (3认同)

Arn*_*rtz 6

  1. f(T&)vsf(T const&)
    这两个函数是不同的,因为第一个签名表明通过引用传递的任何变量都可以被函数修改.因此const float不能传递给第一个函数,第二个函数是编译器唯一可行的选择.nonconst变量可以传递给两者,因此编译器必须选择更合适的变量(如果有的话).标准说,为了调用第二个函数,编译器必须const向任何nonconst变量添加一个,而对于第一个函数,这不是必需的.添加const是一种隐式转换,它是一种"更糟糕"的转换(读取更多转换步骤)而不是添加任何内容.因此,标准要求编译器在传递非对象变量时选择第一个函数.
    如果你想知道:文字和临时文件不能绑定到nonconst引用,那么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!
      //...
    }  
    
    Run Code Online (Sandbox Code Playgroud)

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