使用 vs typedef 指针到noexcept-function不一致
using vs typedef pointer-to-noexcept-function inconsistency
我意识到我可以通过using
为指向noexcept
函数的指针声明一个类型,但是如果我使用typedef
,我被禁止这样的声明。请考虑以下代码:
#include <iostream>
using fptr = void(*)() noexcept;
// typedef void(*FPTR)() noexcept; // fails to compile
void f() noexcept
{
std::cout << "void f() noexcept" << std::endl;
}
void g()
{
std::cout << "void g()" << std::endl;
throw 10;
}
int main()
{
fptr f1 = f;
fptr f2 = g; // why can we do this?
try {
f1();
f2();
}
catch (...)
{
std::cout << "Exception caught" << std::endl;
}
}
如果我取消注释FPTR
声明,我会得到
error: 'FPTR' declared with an exception specification
但是,using
工作正常。使用 gcc4.9 和 gcc5 编译。
我的问题是:
- 为什么会出现这种不一致?
- 为什么我们甚至可以将
using
与noexcept
一起使用,因为我们可以将指针绑定到未声明noexcept
的函数,如行fptr f2 = g;
似乎是与 gcc 相关的错误,即使是 gcc5 也没有捕获它。填写了错误报告
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65382
这似乎是 GCC 中的一个错误;Clang 拒绝两者,因为类型别名或 typedef
s 中不允许异常规范。这可以在以下位置找到:
15.4 异常规范 [规格除外]
2 异常规范应仅出现在函数类型的函数声明符、指向函数类型的指针、对函数类型的引用或指向作为声明或定义的顶级类型的成员函数类型的指针上,或者出现在函数声明符中作为参数或返回类型出现的此类类型上。异常规范不得出现在 typedef 声明或别名声明中。
[...]
该标准还明确指出,两者应保持一致:
7.1.3
typedef
说明符 [dcl.typedef]2 typedef-name 也可以通过别名声明来引入。
using
关键字后面的标识符将成为 typedef-name,标识符后面的可选属性说明符 seq 对应于该 typedef-name。它具有与typedef
说明符引入相同的语义。特别是,它不会定义新类型,并且不应出现在类型ID中。
(强调我的)
回答你的第二个问题:GCC 可能只是忽略了异常规范,因为函数不能只在异常规范上重载 - 它不是函数签名的一部分。这可以在这里找到:
8.3.5 函数
6 [...]返回类型、参数类型列表、ref 限定符和 cv-限定符-seq(但不是默认参数 (8.3.6) 或异常规范 (15.4))是函数类型的一部分。[ 注意:在赋值和初始化指向函数的指针、对函数的引用和指向成员函数的指针期间检查函数类型。
- 在noexcept 规范中是否允许使用"this"?
- 使用 noexcept 运算符 depenendet
- NOEXCEPT 函数调用运算符的说明符_Not_fn
- 参数包内 noexcept 说明符
- 当 noexcept 函数尝试在 gcc 或 clang 中调用非 noexcept 函数时启用警告
- 为什么使用 std::vector 的代码不能编译,但使用 std::unique_ptr 如果没有 noexcept
- 我如何静态断言static_cast是 noexcept?
- "noexcept-expression 由于对......的调用而计算为'假'"是什么意思?
- 如何为C++函数指定 noexcept ?
- 如何知道函数何时抛出以及何时使用noexcept
- 添加noexcept是否会破坏二进制兼容性
- noexcept未通过衰变去除
- 为什么旧的空抛规范被用新的语法"noexcept"重写?
- 在模板中使用 noexcept 运算符
- 在 vs2012 中,lambda 中的 noexcept 如何工作?
- "inline"、"constexpr"或"noexcept"
- 递归 noexcept() 的含义是什么?
- `noexcept`函数中的std :: terminate`调用函数有限-GCC vs clang codegen
- 为什么 std::map 的移动构造函数不是 noexcept?
- 使用 noexcept 和编译器标志来关闭异常