我不明白为什么?我认为兼容性不应该是一个问题,因为在没有说明符的情况下声明的函数实际上将其隐式定义为 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 语言和较旧的 C++ 版本。它在大多数情况下都有效。向函数说明符添加异常会否定这个想法。 C++03和C中没有
noexcept
,会导致函数指针等问题。
让我们思考一下函数在底层是如何工作的。它们基本上是使用保存的(在堆栈上)返回地址进行跳转。它们也通过堆栈传递参数和返回值(并非总是如此,但让我们简化一下)。因此,当您声明一个函数时,您实际上是在告诉函数应该从堆栈中获取多少字节以及在堆栈上留下多少字节。函数声明最重要的是告诉程序通常从函数中期望什么。现在,知道了,异常是否会改变通常传递给函数或从函数传递的信息中的任何内容?他们不这样做。我认为这是异常不属于类型的主要原因。
编辑:在 C++17 中
noexcept
实际上成为了类型系统的一部分,所以你不能这样做:
void (*p)();
void (**pp)() noexcept = &p; //error here
据我所知,这个决定背后的基本原理是允许更好的优化。