为什么函数声明中允许使用 const?

Why is const allowed in function declarations?

在C和C++中,定义函数时可以声明参数const

// without const
void foo(int i)
{
    // implementation of foo()
}

// with const
// const communicates the fact that the implementation of foo() does not modify parameter i
void foo(const int i)
{
    // implementation of foo()
}

不过,从调用者的角度来看,这两个版本是相同的(具有相同的签名)。传递给 foo() 的参数值被复制。 foo() 可能会更改该副本,而不是调用者传递的值。

一切都很好,但是在 声明 foo():

时也允许使用 const
void foo(int i); // normal way to declare foo()

void foo(const int i); // unusual way to declare foo() - const here has no meaning

为什么在声明 foo() 时 C 和 C++ 标准允许 const,即使它在此类声明的上下文中毫无意义?为什么允许这样无意义地使用 const

const 是类型限定符:https://en.cppreference.com/w/cpp/language/cv

因此,它们可以作为语法本身的一部分添加到类型中。我想他们不想以不同方式指定参数和变量。 (这可能会使实施更容易一些?)

然后问题是当它们引用参数本身时它们不参与签名(当它们引用例如参数指向的内存时它们是签名的一部分),正如您在你的问题。

clang-tidy 有一个删除多余的规则 const: https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html

首先,函数参数列表中的const不是没有意义的。考虑这段代码:

void foo(int i)
{
   i++;
   std::cout << i << "\n";
}

如果你加上 const 就不可能了。按值传递的参数如果按值传递的函数的局部变量。将其声明为 const 就是告诉编译器变量 i 在其生命周期内无法更改其值。

还是没什么用?在 C 中,也许。在 C++ 中,这也意味着您不能调用按值传递的 class 类型的非常量方法。假设参数可以是 class 类型的对象,并且是存储在函数外部的某个对象的接口。那么你声明你的函数必须离开那个对象是有意义的 "immutable".

Const 不参与此特殊情况以形成函数签名,因此在同一范围内或在名称查找期间遇到这两个变体会导致程序格式错误。在其他情况下,它可能定义参数值类别的差异。

没有理由禁止非定义声明中函数参数的限定符,允许它允许源代码在定义和任何非定义声明中保持相同的声明。

在定义中,const 和其他限定符具有它们的正常效果,如:

int foo(const int x)
{
    x = 3; // Not permitted.
}

假设我们不希望失去这种行为,允许在定义中使用限定词同时在非声明的声明中禁止它们会使标准不必要地复杂化。此外,这意味着复制定义并将其作为非定义声明粘贴到其他地方的人将不得不进行额外的编辑,并且任何旨在从源文件中收集外部定义以创建包含非定义声明的头文件的软件都将具有进行额外的解析和操作以去除限定符(但仅限顶级限定符,而不是类型内部的限定符,例如 int * const p)。

通常,C 和 C++ 语言不禁止“无用”的东西,例如添加一个常量零(这可能是由预处理器宏的组合引起的,其中对于某些构建选择,某些表达式恰好计算为零选项),孤立的空语句,等等。这些事情无关紧要,除非它们助长了人类犯错的倾向。例如,如果加零总是由于错误而发生(所以它从来没有像上面提到的那样发生)那么禁止它可能是有价值的。但是,如果禁止某事没有任何价值,那么花精力去禁止它就是浪费。