【问题标题】:Declare the same identifier as const variable and member function声明与 const 变量和成员函数相同的标识符
【发布时间】:2018-08-21 05:58:02
【问题描述】:

我写了下面这段代码

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

【问题讨论】:

  • 在 Clang 上编译,而不是在 GCC 上。您应该在问题中填写完整的错误消息。
  • 在 MSVC 2018 上编译。
  • std::cout &lt;&lt; "array size:"&lt;&lt;sizeof(array)/N &lt;&lt; std::endl; --> std::cout &lt;&lt; "array size:" &lt;&lt; std::size(array) &lt;&lt; std::endl;

标签: c++ variables scope declaration


【解决方案1】:

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

但是,声明类成员数据时并非如此。此时(当指定array 时),该类不被认为是完整的。所以N只能引用之前看到的,也就是说它必须是全局常量。

Clang 接受它,但发出 6 (sizeof(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 说明符,
  • 合同条件([dcl.attr.contract]),或
  • 默认成员初始化器

在类的成员规范内。

【讨论】:

  • 我很困惑。你说在数组的声明器中,类是不完整的。好的。但是你说在数组之前定义枚举会使数组使用枚举值而不是常量。为什么?
  • @Rakete1111 - 因为它是之前定义的,并且不依赖于在完整的类上下文中来隐藏全局常量。
  • @Rakete1111 - 虽然我确实捏造了措辞。应该是“定义类成员数据时”。现已修复
  • 我无法让 g++ 在 7.3.0 中向 -pedantic-errors 抱怨,即使在添加 -Wall -Wextra -Werror 之后也是如此。我错过了什么吗?
  • @molbdnilo - Rakete1111 所说的。事实上,即使没有学究气,它也会抱怨。
【解决方案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;   
      }
};

那么,用于定义arrayN就是在enum中定义的那个。

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

【讨论】:

    【解决方案3】:

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

    根据[basic.scope.class]/2

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-19
      • 1970-01-01
      • 1970-01-01
      • 2020-09-29
      • 1970-01-01
      • 2012-10-17
      • 2018-01-12
      相关资源
      最近更新 更多