为什么我们需要[basic.scope.class] / 2?

时间:2017-07-04 19:58:30

标签: c++ class scope language-lawyer

我了解[basic.scope.class]/5中示例中显示的所有错误均指[basic.scope.class]/2

[basic.scope.class] / 2:

  

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

但我想知道的是,为什么我们首先需要这种语言规则呢?

例如,考虑[basic.scope.class] / 5中的第一个例子:

如果语言允许这样做会有什么问题,即v[i]下面有一个元素的数组

enum { i = 1 };

class X {
  char  v[i];
  enum { i = 2 };
};

以及后面示例中的两个元素的数组?

enum { i = 1 };

class X {
  enum { i = 2 };
  char  v[i];
};

2 个答案:

答案 0 :(得分:1)

至少有两个原因。

首先,每个翻译单元中可能没有enum { i = 1 };,其中包含定义X的标头。结果将是X的定义冲突。

其次,假设在第一个例子中,该类还有一个成员函数数组后定义:

void show() const {
    for (int idx = 0; idx < i; ++idx)
        std::cout << v[idx];
}

编译器应该如何确定i在这里应该与第一个 i相同而不是第二个

答案 1 :(得分:0)

在此代码段中

enum { i = 1 };

class X {
  char  v[i];
  enum { i = 2 };
};

当声明数组时,名称i引用在外部作用域中声明的枚举数,并且该数组被声明为只有一个元素。

如果要交换数据成员的声明,我们将得到另一个结果,即在类定义中声明的枚举器隐藏在外部作用域中声明的枚举数。结果,数组有两个元素。

enum { i = 1 };

class X {
  enum { i = 2 };
  char  v[i];
};

这是很难找到错误的原因。

例如,让我们假设该类有一个构造函数,在该构造函数中初始化数组。

enum { i = 1 };

class X {
public:
    X()
    {
        for (size_t j; j < i; j++) v[j] = 'A' + j;
    }
private:
    char  v[i];
    enum { i = 2 };
};

正如您所看到的,将会有未定义的行为。在构造函数中,名称i引用类中声明的枚举器,而在数组本身的声明中,名称i引用在外部作用域中声明的枚举器。