在 C++14 中使用 decltype(auto) 声明静态数据成员

Declaring a Static Data Member with decltype(auto) in C++14

本文关键字:auto 声明 静态 数据成员 decltype C++14      更新时间:2023-10-16

此代码是否符合标准?

class Example {
public:
static int x;
};
decltype(auto) Example::x = 1;
int main(){ return 0; }

Clang 3.9.1 编译成功,但 gcc 6.3.0 失败:error: conflicting declaration 'decltype(auto) Example::x'

C++14 标准 (ISO/IEC 14882:2014),第 7.1.6.4 节,第 5 段(强调我的):

占位符类型还可用于在选择语句 (6.4) 或迭代语句 (6.5) 的条件中声明变量,在新表达式(5.3.4) 的新类型 ID 或类型ID 中的类型说明符 seq中声明变量,在for 范围声明中,以及声明具有大括号或等于初始值设定项的静态数据成员,该初始值设定项出现在类定义的成员规范中 (9.4.2).

(重新)声明严格来说并不在类定义的成员规范内,但我看不出有任何充分的理由禁止它。此外,它还可以看作是命名空间范围内变量(静态数据成员变量)的(重新)声明,这在第 4 段中是允许的:

使用 auto 或 decltype(auto) 声明的变量的类型是从其初始值设定项推导出来的。在块 (6.3)、命名空间范围 (3.3.6) 和 for-init 语句 (6.5.3) 中声明变量时,允许使用此用法。

有一个类似的C++11帖子:为什么C++11"auto"关键字不适用于静态成员? 但是,只有一个答案,然后在评论中开始辩论。此外,在这种情况下,clang 通常更可靠,根据该答案,clang 将是错误的,而 gcc 是正确的。

似乎 gcc 变得混乱,因为它试图从初始化中的右值推断x的类型,而不是Example类中的声明。这可能会导致两种类型之间的不一致,使您看起来像是在定义具有相同名称的新变量。

如果我理解正确,您正在寻找的行为可以通过使用从变量声明显式推断类型的宏来使用符合标准的代码来实现:

#define auto_typed_init(a) decltype(a) a
(...)
auto_typed_init(Example::x) = 2;

但是,我不明白为什么在这种情况下标准偏爱初始值设定项,正如本答案中所解释的那样:为什么 C++11'auto' 关键字不适用于静态成员?