我了解[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];
};
答案 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
引用在外部作用域中声明的枚举器。