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

时间:2018-08-21 05:58:02

标签: c++ variables scope declaration

我写了下面的代码

#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。编译器如何解析变量的名称声明?

3 个答案:

答案 0 :(得分:6)

在成员函数(甚至是内联定义的成员函数)的范围内,该类也被认为是完整的 1 。因此,使用N必须使用成员枚举器。并且其值必须为3。

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

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

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

...否则,我们可以使用范围解析来引用“正确的N”

sizeof(array) / ::N

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


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

  

[class.mem]/6

     

一个类的完整类上下文是

     
      
  • 功能主体([dcl.fct.def.general]),
  •   
  • 默认参数([dcl.fct.default]),
  •   
  • noexcept-specifier
  •   
  • 合同条件([dcl.attr.contract]),或
  •   
  • 默认成员初始化程序
  •   
     

在类的成员规范内。

答案 1 :(得分:2)

在线

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;   
      }
};

然后,用于定义N的{​​{1}}是在array中定义的那个。

PS 这对于理解语言很有用,但是请不要在实际应用中使用这种编码风格。

答案 2 :(得分:1)

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

根据[basic.scope.class]/2

  

在S类中使用的名称N在上下文中以及在S的完整范围中进行重新评估时应引用相同的声明。对于此规则的违反,无需进行诊断。

在声明的上下文中,N被解析为引用::N,但是在X的完整范围(现在所有成员都可见)中,N解析为引用枚举器X::N,因此程序格式错误;无需诊断。