为什么函数参数中的const限定符用于重载分辨率?

时间:2012-07-25 08:36:31

标签: c++ overloading overload-resolution

  

可能重复:
  Functions with const arguments and Overloading

我对overloading和const声明规则感到很困惑。 这有两件事让我感到困惑,也许你可以帮助我找到更深层次的误解,导致他们对我感到困惑。 ;)

第一期:

我的编译器允许这样:

void f(int & x) {
  std::cout << "plain f" << std::endl;
}
void f(const int & x) {
  std::cout << "const f" << std::endl;
}

但是以下会导致编译错误(函数已经有一个正文):

void f(int x) {
  std::cout << "plain f" << std::endl;
}
void f(const int x) {
  std::cout << "const f" << std::endl;
}

我认为这是有道理的,因为我认为const只是告诉编译器传递的对象没有改变,在第二种情况下它仍然被复制。但如果这是正确的,为什么我可以使用const?

重载函数

换句话说,为什么我使用编译版本并调用这样的函数:

  int x1 = 5;
  const int x2 = 5;
  f(x1);
  f(x2);

我得到“普通f”和“const f”而不是“const f”两次吗?显然现在我也使用const来告诉编译器调用哪个函数不仅引用不会改变。这变得更加混乱,因为如果我删除“普通”版本它工作得很好并且两次调用“const”版本。

现在我的实际问题是什么?我想知道这种行为背后的想法是什么,因为否则记住它是非常困难的。

2 个答案:

答案 0 :(得分:4)

n3337 13.1

  

[注意:如8.3.5中所述,函数声明具有   等效参数声明声明相同的函数和   因此不能超载:仅在存在或不存在时才发生

     

- di3的参数声明   const和/或volatile的等价物。也就是说,const和   当时,将忽略每个参数类型的volatile类型说明符   确定正在声明,定义或调用哪个函数。 [   示例:

typedef const int cInt;
int f(int);
int f(const int); // redeclaration of f(int)
int f(int) { /* ... */ } // definition of f(int)
int f(cInt) { /* ... */ } // error: redefinition of f(int)
     

- 结束   例子]只有最外面的const和volatile类型说明符   此参数类型规范的级别将被忽略   时尚; const和volatile类型说明符隐藏在参数中   类型规范是重要的,可用于区分   重载函数声明.124特别是对于任何类型的T,   “指向T的指针”,“指向const T的指针”和“指向易失性T的指针”   被认为是不同的参数类型,如“对T的引用”   “引用const T”和“引用volatile T”。

答案 1 :(得分:1)

  

我认为const只是告诉编译器对象是什么   传递不会改变,在第二种情况下,它仍然被复制

你是对的。因为在第二种情况下它仍然被复制,因此const对调用者没有任何影响,标准定义void f(const int x)void f(int x)具有相同的签名。因此它们发生碰撞,你试图两次定义相同的函数。

因为在第一种情况下,尚未被复制,void f(const int &x)void f(int &x)具有不同的签名。因此他们超载。

在你的第一种情况下,禁止以int&f作为参数调用x2版本,因为这将创建一个对const对象的非const引用而没有任何显式看得见。这样做会破坏const系统的目的(如果你想破坏const-safety,你必须明确地使用强制转换)。因此,使用参考参数进行函数的常量和非常量重载是有意义的。

在第二种情况下,副本源的常量与目标的常量之间没有关系。您可以从非常量变量初始化const变量,或从常量变量初始化const变量。这不会导致任何问题,也不会破坏const安全性。这就是为什么标准通过定义f的两个“不同”版本实际上是相同的功能来帮助明确这一点。