声明与 const 变量和成员函数相同的标识符

Declare the same identifier as const variable and member function

本文关键字:标识符 函数 成员 const 变量 声明      更新时间:2023-10-16

我写了以下一段代码

#include <iostream>
const int N = 5;
class X
{
public:
int array[N];
void foo()
{
std::cout << "array size:"<<sizeof(array)/N << std::endl;   
}
enum
{
N = 3    
};
};
int main()
{
X x;
x.foo();
} 

上述代码无法使用 GCC 编译:

<source>:13:8: error: declaration of 'N' [-fpermissive]
N = 3
^
<source>:2:11: error: changes meaning of 'N' from 'const int N' [-fpermissive]
const int N = 5;
^

从编译时开始,数组被定义为一个由五个整数组成的数组,N 被定义为 5。 编译器如何解析变量的名称声明?

在成员函数的作用域内(即使是内联定义的函数(,该类被认为是完整的1。因此,使用N那里必须使用成员枚举器。并且其值必须为 3。

但是,在声明类成员数据时,情况并非如此。此时(指定array时(,该类不被视为完整。因此,N只能引用之前看到的内容,这意味着它必须是全局常数。

叮当接受它,但发出6(sizeof(int) * 5 / 3(。GCC (8( 没有,但它并不是真正的无效代码。只是容易出错。更好地定义的方法是在定义数组之前将枚举器移动到

enum { N = 3 };
int array[N];

。或者如果我们不这样做,那么我们可以使用范围解析来引用"正确的 N">

sizeof(array) / ::N

重新排列类定义会更好,因为它仍然不会出错(我们可以忘记使用限定::N(。


1:来自最新的C++标准草案

[类记忆]/6

类的完整类上下文是

  • 函数体 ([dcl.fct.def.general](,
  • 默认参数 ([dcl.fct.default](,
  • 无例外说明符,
  • 合同条件([dcl.attr.contract](,或
  • 默认成员初始值设定项

在类的成员规范中。

在行中

int array[N];

N是全球N

在函数foo()Nenum中定义的那个。

foo()的定义中,类的定义用于解析名称。但是,在成员变量的声明中,只有该行之前的声明用于解析名称。

如果您将课程更改为

class X
{
public:
enum
{
N = 3    
};
int array[N];
void foo()
{
std::cout << "array size:"<<sizeof(array)/N << std::endl;   
}
};

然后,用于定义arrayN是第enum中定义的。

PS这对于理解语言很有用,但请不要在现实世界的应用程序中使用这种编码风格。

问题来自声明int array[N];

根据 [basic.scope.class]/2:

在 S 类中使用的名称 N 应在其上下文中引用相同的声明,并且在 S 的完整范围内重新评估时,无需诊断违反此规则的情况。

在声明的上下文中,N被解析为引用::N,但在已完成的X范围内(所有成员现在都可见(,N被解析为引用枚举器X::N,因此程序格式不正确;不需要诊断。