声明与 const 变量和成员函数相同的标识符
Declare the same identifier as const variable and member function
我写了下面这段代码
#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。编译器如何解析变量的名称声明?
在成员函数的范围内(即使是内联定义的),class 被认为是完整的1。因此,使用 N
必须使用成员枚举器。它的值必须是 3.
但是,声明 class 成员数据时情况并非如此。此时(指定 array
时),class 未被视为完整。所以N
只能引用之前看到的,也就是说必须是全局常量。
Clang 接受它,但发出 6
(sizeof(int) * 5 / 3
)。 GCC (8) 没有,但它并不是真正的无效代码。这只是容易出错。更好定义的方法是将枚举器移动到数组定义之前
enum { N = 3 };
int array[N];
...或者如果我们不这样做,那么我们可以使用范围解析来引用 "correct N"
sizeof(array) / ::N
重新排列 class 定义会更好,因为它不会仍然容易出错(我们可以忘记使用合格的 ::N
)。
1: 来自最新的C++标准草案
A complete-class context of a class is a
- function body ([dcl.fct.def.general]),
- default argument ([dcl.fct.default]),
- noexcept-specifier,
- contract condition ([dcl.attr.contract]), or
- default member initializer
within the member-specification of the class.
在行
int array[N];
N
是全局 N
.
在函数foo()
中,N
是在enum
中定义的N
。
在foo()
的定义里面,class的定义是用来解析名字的。但是,在成员变量的声明中,只有该行之前的声明用于解析名称。
如果您将 class 更改为
class X
{
public:
enum
{
N = 3
};
int array[N];
void foo()
{
std::cout << "array size:"<<sizeof(array)/N << std::endl;
}
};
那么,用来定义array
的N
就是enum
中定义的N
。
PS
这对于理解语言很有用,但请永远不要在现实世界的应用程序中使用这种编码风格。
问题来自声明int array[N];
。
A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.
在声明的上下文中,N
解析为引用 ::N
,但在 X
的完整范围内(所有成员现在可见),N
解析为引用枚举数 X::N
,因此程序格式错误;不需要诊断。
我写了下面这段代码
#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。编译器如何解析变量的名称声明?
在成员函数的范围内(即使是内联定义的),class 被认为是完整的1。因此,使用 N
必须使用成员枚举器。它的值必须是 3.
但是,声明 class 成员数据时情况并非如此。此时(指定 array
时),class 未被视为完整。所以N
只能引用之前看到的,也就是说必须是全局常量。
Clang 接受它,但发出 6
(sizeof(int) * 5 / 3
)。 GCC (8) 没有,但它并不是真正的无效代码。这只是容易出错。更好定义的方法是将枚举器移动到数组定义之前
enum { N = 3 };
int array[N];
...或者如果我们不这样做,那么我们可以使用范围解析来引用 "correct N"
sizeof(array) / ::N
重新排列 class 定义会更好,因为它不会仍然容易出错(我们可以忘记使用合格的 ::N
)。
1: 来自最新的C++标准草案
A complete-class context of a class is a
- function body ([dcl.fct.def.general]),
- default argument ([dcl.fct.default]),
- noexcept-specifier,
- contract condition ([dcl.attr.contract]), or
- default member initializer
within the member-specification of the class.
在行
int array[N];
N
是全局 N
.
在函数foo()
中,N
是在enum
中定义的N
。
在foo()
的定义里面,class的定义是用来解析名字的。但是,在成员变量的声明中,只有该行之前的声明用于解析名称。
如果您将 class 更改为
class X
{
public:
enum
{
N = 3
};
int array[N];
void foo()
{
std::cout << "array size:"<<sizeof(array)/N << std::endl;
}
};
那么,用来定义array
的N
就是enum
中定义的N
。
PS 这对于理解语言很有用,但请永远不要在现实世界的应用程序中使用这种编码风格。
问题来自声明int array[N];
。
A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.
在声明的上下文中,N
解析为引用 ::N
,但在 X
的完整范围内(所有成员现在可见),N
解析为引用枚举数 X::N
,因此程序格式错误;不需要诊断。