使用vs typedef指向noexcept-函数不一致

vso*_*tco 3 c++ exception c++11

我意识到我可以为一个指向noexcept函数的指针声明一个类型using,但如果我使用的话,我禁止这样的声明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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我取消对FPTR声明的注释,我就会得到

error: 'FPTR' declared with an exception specification

但是,using工作得很好.用gcc4.9和gcc5编译.

我的问题是:

  1. 为什么这种不一致?
  2. 为什么我们甚至可以使用using,noexcept因为我们可以将指针绑定到未声明的函数noexcept,如行中所示fptr f2 = g;

似乎是一个与gcc相关的bug,即使gcc5也没有抓住它.填写错误报告

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65382

Dan*_*rey 7

这似乎是海湾合作委员会的一个错误; Clang拒绝两者,因为类型别名或typedefs中不允许异常规范.这可以在以下位置找到:

15.4例外规范[except.spec]

2一种异常规范应在函数声明为函数类型只出现,函数指针类型,参照功能类型或成员函数指针类型,它是一个声明或定义的顶级类型,或者在这样的类型在函数声明符中显示为参数或返回类型.一个异常规范,不得出现在typedef声明或别名声明.

[...]

该标准还明确指出两者应该是一致的:

7.1.3 typedef说明符[dcl.typedef]

2typedef的名称也可以通过一个被引入别名声明.using关键字后面的标识符变为typedef-name,并且该标识符后面的可选attribute-specifier-seq属于该typedef-name.它具有与typedef说明符引入的语义相同的语义.特别是,它没有定义新类型,它不应出现在type-id中.

(强调我的)

回答你的第二个问题:GCC可能只是忽略了异常规范,因为函数不能仅仅在异常规范上重载 - 它不是函数签名的一部分.这可以在这里找到:

8.3.5函数[dcl.fct]

6 [...]返回类型,参数类型列表,ref-qualifiercv-qualifier-seq,但不是默认参数(8.3.6)或异常规范(15.4),是功能类型.[ 注意:在指向函数的指针和函数的引用以及指向成员函数的指针的赋值和初始化期间,将检查函数类型.- 结束说明 ]