使用 vs typedef pointer-to-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
一起使用,因为我们可以将指针绑定到未声明 [=11=] 的函数,如行 fptr f2 = g;
好像是gcc相关的bug,连gcc5都抓不到。填写错误报告
这似乎是 GCC 中的一个错误; Clang 拒绝两者,因为类型别名或 typedef
s 中不允许异常规范。这可以在以下位置找到:
15.4 Exception specifications [except.spec]
2 An exception-specification shall appear only on a function declarator for a function type, pointer to function type, reference to function type, or pointer to member function type that is the top-level type of a declaration or definition, or on such a type appearing as a parameter or return type in a function declarator. An exception-specification shall not appear in a typedef declaration or alias-declaration.
[...]
标准还明确表示两者应该一致:
7.1.3 The typedef
specifier [dcl.typedef]
2 A typedef-name can also be introduced by an alias-declaration. The identifier following the using
keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by the typedef
specifier. In particular, it does not define a new type and it shall not appear in the type-id.
(强调我的)
回答你的第二个问题:GCC 可能只是忽略了异常规范,因为不能仅在异常规范上重载函数——它不是函数签名的一部分。可以在这里找到:
8.3.5 Functions [dcl.fct]
6 [...] The return type, the parameter-type-list, the ref-qualifier, and the cv-qualifier-seq, but not the default arguments (8.3.6) or the exception specification (15.4), are part of the function type. [ Note: Function types are checked during the assignments and initializations of pointers to functions, references to functions, and pointers to member functions. — end note ]
我意识到我可以通过 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
一起使用,因为我们可以将指针绑定到未声明 [=11=] 的函数,如行fptr f2 = g;
好像是gcc相关的bug,连gcc5都抓不到。填写错误报告
这似乎是 GCC 中的一个错误; Clang 拒绝两者,因为类型别名或 typedef
s 中不允许异常规范。这可以在以下位置找到:
15.4 Exception specifications [except.spec]
2 An exception-specification shall appear only on a function declarator for a function type, pointer to function type, reference to function type, or pointer to member function type that is the top-level type of a declaration or definition, or on such a type appearing as a parameter or return type in a function declarator. An exception-specification shall not appear in a typedef declaration or alias-declaration.
[...]
标准还明确表示两者应该一致:
7.1.3 The
typedef
specifier [dcl.typedef]2 A typedef-name can also be introduced by an alias-declaration. The identifier following the
using
keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by thetypedef
specifier. In particular, it does not define a new type and it shall not appear in the type-id.
(强调我的)
回答你的第二个问题:GCC 可能只是忽略了异常规范,因为不能仅在异常规范上重载函数——它不是函数签名的一部分。可以在这里找到:
8.3.5 Functions [dcl.fct]
6 [...] The return type, the parameter-type-list, the ref-qualifier, and the cv-qualifier-seq, but not the default arguments (8.3.6) or the exception specification (15.4), are part of the function type. [ Note: Function types are checked during the assignments and initializations of pointers to functions, references to functions, and pointers to member functions. — end note ]