为什么函数参数中的const限定符用于重载解析

Why are const qualifiers in function arguments used for overloading resolution?

本文关键字:用于 重载 参数 函数 const 为什么      更新时间:2023-10-16

可能重复:
带有常量参数和重载的函数

重载和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"answers"const f"而不是"const f"吗?显然,现在我还使用const来告诉编译器要调用哪个函数,不仅引用没有改变。这会变得更令人困惑,因为如果我删除"普通"版本,它会正常工作,并调用"const"版本两次。

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

n3337 13.1

[注意:如8.3.5所述,具有等效的参数声明声明相同的函数和因此不能过载:ffer仅在存在或不存在的情况下

--di3的参数声明的const和/或volatile是等效的。也就是说,const和当确定要声明、定义或调用的函数。[示例:

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)

--完example]只有最外层的const和volatile类型说明符此中忽略参数类型规范的级别时尚参数中隐藏的const和volatile类型说明符型号规格很重要,可用于区分重载函数声明124特别是对于任何类型T,"指针到T"、"指针到常量T"answers"指针到易失性T"被认为是不同的参数类型,如"对T的引用"引用常量T"answers"引用挥发性T"

我以为const只是用来告诉编译器对象通过的不会更改,在第二种情况下,它无论如何都会被复制

你是对的。因为在第二种情况下,它无论如何都是被复制的,所以const对调用者没有什么区别,所以标准定义void f(const int x)void f(int x)具有相同的签名。因此,它们发生了碰撞,你试图定义同一个函数两次。

因为在第一种情况下,它无论如何都不是复制的,所以void f(const int &x)void f(int &x)具有不同的签名。因此它们过载。

在第一种情况下,禁止使用x2作为参数调用fint&版本,因为这将创建对const对象的非常量引用,而看不到任何显式强制转换。这样做违背了const系统的目的(也就是说,如果你想破坏const的安全性,你必须通过强制转换显式地这样做)。因此,对具有引用参数的函数进行常量和非常量重载是有意义的。

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