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

Sar*_*ien 10 c++ overloading overload-resolution

可能重复:
具有const参数和重载的函数

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

首要问题:

我的编译器允许这样:

void f(int & x) {
  std::cout << "plain f" << std::endl;
}
void f(const int & x) {
  std::cout << "const f" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

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

void f(int x) {
  std::cout << "plain f" << std::endl;
}
void f(const int x) {
  std::cout << "const f" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

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

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

  int x1 = 5;
  const int x2 = 5;
  f(x1);
  f(x2);
Run Code Online (Sandbox Code Playgroud)

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

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

For*_*veR 5

n3337 13.1

\n\n
\n

[ 注意:按照 8.3.5 中的规定,具有等效参数声明的函数声明声明相同的函数,因此不能重载:仅在存在或不存在时才有效

\n\n

\xe2\x80\x94 const 和/或 volatile 的 di3\n 等效的参数声明。也就是说,在确定正在声明、定义或调用哪个函数时,将忽略每个参数类型的 const 和 volatile 类型说明符。[\n 示例:

\n\n
typedef const int cInt;\nint f(int);\nint f(const int); // redeclaration of f(int)\nint f(int) { /* ... */ } // definition of f(int)\nint f(cInt) { /* ... */ } // error: redefinition of f(int)\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x80\x94 end\n 示例 ] 以这种方式仅忽略参数类型规范最外层的 const 和 volatile 类型说明符;隐藏在参数类型规范中的 const 和 volatile 类型说明符非常重要,可用于区分重载函数声明。124 特别是,对于任何类型 T,\n \xe2\x80\x9c 指向 T 的指针,\xe2 \x80\x9d \xe2\x80\x9c 指向 const T 的指针、\xe2\x80\x9d 和 \xe2\x80\x9c 指向 volatile T\xe2\x80\x9d 的指针被视为不同的参数类型,\xe2\x80 也是如此\x9c 对 T 的引用,\xe2\x80\x9d\n \xe2\x80\x9c 对 const T 的引用,\xe2\x80\x9d 和 \xe2\x80\x9c 对易失性 T 的引用。\xe2\x80\x9d

\n
\n

  • @CorporalTouchy:当您按值传递参数时,您会创建一个副本。该副本是否为“const”与调用代码的行为无关,因此没有理由在调用方区分它们。 (2认同)

Ste*_*sop 2

我认为 const 只是告诉编译器传递的对象没有改变,在第二种情况下无论如何它都会被复制

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

因为在第一种情况下它无论如何都不会被复制,void f(const int &x)并且void f(int &x)具有不同的签名。因此他们超载。

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

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