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

时间:2015-03-10 21:21:24

标签: 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;
    }
}

如果我取消注释FPTR声明,我就会

  

error: 'FPTR' declared with an exception specification

然而,using工作正常。用gcc4.9和gcc5编译。

我的问题是:

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

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

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

1 个答案:

答案 0 :(得分:7)

这似乎是海湾合作委员会的一个错误; Clang拒绝两者,因为类型别名或typedef s中不允许例外规范。这可以在以下网址找到:

  

15.4异常规范[except.spec]

     

2 异常规范只出现在函数类型的函数声明符,函数类型的指针,函数类型的引用或成员函数类型的指针上这是声明或定义的顶级类型,或者在函数声明符中显示为参数或返回类型的类型。 例外规范不得出现在typedef声明或 alias-declaration 中。

     

[...]

该标准还明确规定两者应保持一致:

  

7.1.3 typedef说明符[dcl.typedef]

     

2 alde-name 也可以通过 alias-declaration 引入。 using关键字后面的标识符变为 typedef-name ,并且可选的 attribute-specifier-seq 跟随 typedef-name <的标识符/ em>的。 它具有与typedef说明符引入的语义相同的语义。特别是,它没有定义新类型,它不会出现在 type-id 中。

(强调我的)

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

  

8.3.5函数[dcl.fct]

     

6 [...]返回类型,参数类型列表, ref-qualifier cv-qualifier-seq < / em>,但不是默认参数(8.3.6)或异常规范(15.4),是函数类型的一部分。 [注意:在指向函数的指针和函数的引用以及指向成员函数的指针的赋值和初始化期间,会检查函数类型。 - 结束记录]