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

Why is const allowed in function declarations?

本文关键字:const 函数 声明 为什么      更新时间:2023-10-16

在 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

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

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

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

那么问题来了,正如你在问题中所说,当他们引用论点本身时,它们不参与签名(例如,当他们提到论点所指向的内存时,它们是签名的一部分(。

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

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

在定义中,const和其他限定符具有其正常效果,如下所示:

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

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

通常,C 和 C++ 语言不禁止"无用"的事情,例如添加常量零(这可能来自预处理器宏的组合,其中某些表达式碰巧在某些构建选项选择时计算为零(、隔离的空语句等。这些事情并不重要,除非它们有助于人类犯错误的倾向。例如,如果添加零总是由于错误而发生(因此它从未发生过如上所述的结果(,那么禁止它可能具有价值。但是,如果禁止某事没有价值,那么花费精力禁止它就是浪费。

首先,函数参数的 lis 中的常量并非毫无意义。请考虑以下代码:

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

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

还是没多大用处?在 C 中,也许吧。在C++这也意味着您不能调用按值传递的类型类的非 const 方法。假设参数可以是类类型的对象,并且是存储在函数外部的某个对象的接口。然后,声明函数必须使该对象保持"不可变"确实有意义。

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