首页 > 解决方案 > 为什么 Clang 和 MSVC 不喜欢带有一组冗余括号的成员 typedef 声明?

问题描述

考虑

using foo = int;

struct A {
    typedef A (foo)();
};

GCC 和 ICC 接受该片段,而 Clang 和 MSVC 拒绝它。Clang 的错误信息是

<source>:4:15: error: function cannot return function type 'void ()'
    typedef A (foo)();
              ^
<source>:4:13: error: typedef name must be an identifier
    typedef A (foo)();
            ^
2 errors generated.

MSVC 说

<source>(4,15): error C2091: function returns function
    typedef A (foo)();
              ^

现场演示

为什么 Clang 和 MSVC 会产生此错误?哪些编译器是正确的?

(我专门从标准或任何缺陷报告中寻找报价。)

标签: c++language-lawyertypedef

解决方案


Clang 和 MSVC 都忽略了typedef说明符并将声明读取为构造函数的声明(即A构造函数名称),接受参数类型(foo)(即(int))并“返回”由尾括号表示的函数类型()

是的,构造函数没有返回类型;但是如果他们确实有返回类型,他们就会有返回类型A,所以最后的附加()项使这些编译器认为你现在有一个返回类型为函数类型的构造函数A()

注意到以下“类似”声明具有类似的错误消息来支持这一点:

A (foo)();
typedef ~A(foo)();

此外,通过添加,static我们可以从 MSVC 中获得一个启发性的错误消息:

A static (int)();
error C2574: '(__cdecl *A::A(int))(void)': cannot be declared static

对于解决方法:在 Clang(但不是 MSVC)下,您可以将说明typedef符移到右侧,或使用详细的类型说明符:

A typedef (foo)();
typedef struct A (foo)();

在所有编译器下,您都可以删除或添加括号:

typedef A foo();
typedef A ((foo))();

而且您始终可以更新为类型别名:

using foo = A();

推荐阅读