为什么 "noexcept" 说明符不是函数类型的一部分?

Why isn't the "noexcept" specifier part of the function type?

我不明白为什么?我不认为兼容性应该是一个问题,因为在没有说明符的情况下声明的函数实际上将其隐式定义为 false。如果它是关于名称修改的——我们是否可以假设旧的(现有的)将暗示 noexcept(false) 并向 noexcept(true) 的修改中添加另一个新符号。

这在使用模板时会很有用,因为现在比较函数类型和 noexcept 说明符应该分开进行。我的基本意思是:

int func() noexcept(true), func_1() noexcept(false);

decltype(func) == decltype(func_1); //this now equals true

但另一方面,如果我们通过使用指针或引用进行函数赋值,则检查 noexcept 说明符,就好像它是类型的一部分一样:

int (&refFunc)() noexcept(true) = func_1; //target exception specification is not superset of source

int (&refFunc)() noexcept(true) = func; //ok

所以现在实现全功能匹配应该通过执行类型和 noexcept 检查来完成,这有点复杂:

decltype(func) == decltype(func_1) && noexcept(func()) == noexcept(func_1()); //this now equals false

想象一下如果函数有参数:

int func(int, double) noexcept(true), func_1(int, double) noexcept(false);

decltype(func) == decltype(func_1) && noexcept(func(int{}, double{})) == noexcept(func_1(int{}, double{})); //this now equals false

C/C++03 兼容性

最重要的 C++ 基本思想之一是向后兼容 C 语言和旧的 C++ 版本。它在大多数情况下都有效。向函数说明符添加异常会否定这个想法。 C++03和C中没有noexcept,会导致函数指针等问题

低级别

让我们思考一下函数在底层是如何工作的。它们基本上是用保存的(在堆栈上)return 地址跳转的。他们也通过堆栈传递参数和 return 值(并非总是如此,但让我们稍微简化一下)。所以,当你声明一个函数时,你实际上是在告诉函数应该从堆栈中取出多少字节以及它留在堆栈上的字节数。函数声明最重要的是告诉程序通常期望从函数中得到什么。现在,知道了,异常会改变通常传递给 to/from 函数的信息中的任何内容吗?他们没有。我认为这是异常不属于类型的主要原因。

编辑:

在 C++17 中 noexcept 实际上成为了类型系统的一部分,所以你不能这样做:

void (*p)();
void (**pp)() noexcept = &p; //error here

据我所知,这个决定背后的理由是允许更好的优化。

从 C++17 开始,noexcept 说明符是函数类型的一部分。

Reference

The noexcept-specification is a part of the function type and may appear as part of any function declarator. (since C++17)