10

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

我对重载和 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);

我得到“plain f”和“const f”而不是“const f”两次?显然现在我也使用 const 来告诉编译器调用哪个函数,不仅引用不会改变。这变得更加令人困惑,因为如果我删除“普通”版本,它就可以正常工作并两次调用“const”版本。

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

4

2 回答 2

4

n3337 13.1

[注:如 8.3.5 所述,具有等效参数声明的函数声明声明相同的函数,因此不能重载:仅在存在或不存在时提供

— const 和/或 volatile 的 di3 的参数声明是等价的。也就是说,在确定声明、定义或调用哪个函数时,将忽略每个参数类型的 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”和“指向volatile T”被认为是不同的参数类型,“reference to T”、“reference to const T”和“reference to volatile T”也是如此。</p>

于 2012-07-25T08:46:16.070 回答
2

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

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

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

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

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

于 2012-07-25T09:39:29.793 回答