使用 vs typedef 指针到noexcept-function不一致

using vs typedef pointer-to-noexcept-function inconsistency

本文关键字:noexcept-function 不一致 指针 vs typedef 使用      更新时间:2023-10-16

我意识到我可以通过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 编译。

我的问题是:

  1. 为什么会出现这种不一致?
  2. 为什么我们甚至可以将usingnoexcept一起使用,因为我们可以将指针绑定到未声明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))是函数类型的一部分。[ 注意:在赋值和初始化指向函数的指针、对函数的引用和指向成员函数的指针期间检查函数类型。