类中成员声明重新排序规则

16

我正在阅读C++14标准N3797,遇到了3.3.7/1:

如果在类中重新排序成员声明可以产生另一种有效程序(在(1)和(2)下),则该程序是不正确的,无需进行诊断。

这里的(1)和(2)是:

1)在类中声明的名称的潜在作用域不仅包括紧随名称的声明点之后的声明区域,还包括该类中非静态数据成员的所有函数体、默认参数、异常规格说明和括号等于初始化项(包括嵌套类中的这些内容)。

2)在类S中使用的名称N应当在其上下文中引用同一声明,并在S的完成作用域中重新评估时引用同一声明。对于违反此规则的情况,无需进行诊断。

也就是说,如果我们编写以下内容:

class A
{
    int a;
    int b;
}

那么程序就是非法的。重新排列成员声明会产生另一个有效的程序:

class A
{
    int b;
    int a;
}

我可能没有正确理解这个规则吗?


当然,这不会创建一个“替代有效程序”。它可能看起来不同,但是它将编译并执行相同的操作。 - Fantastic Mr Fox
1个回答

18
“备选有效程序”是指类中元素的每种排序都可以产生一个有效的程序解释,但程序的含义取决于排序方式而发生变化
在您的情况下,更改ab的顺序是允许的,但是由于它们的相对顺序不会影响程序的含义,因此行为是被定义好的。
为了实现这一点,必须使用类中已经定义过其他含义的名称。例如:
typedef void *T;

struct whatever {
    T a;
    typedef long T;
};

在这里,声明变量 a 和定义类型 T 的相对顺序影响代码的含义。当前代码的写法中,当解析 T a; 时,全局的 typedef void *T; 处于作用域内,使得 a 的类型为 void *
然而,如果我们将两者重新排列成如下形式:
typedef void *T;

struct whatever {
    typedef long T;
    T a;
};

...T a;相当于long a;。由于两个声明的相对顺序不同,程序的含义也不同,因此行为是未定义的。


2
你能举个例子说明程序的顺序影响其含义吗? - Fantastic Mr Fox
似乎我开始理解了。如果是这样,重排之前和之后的行为可能会有所不同。我的理解正确吗? - user2953119
2
是的。我已经添加了一个例子。 - Jerry Coffin
if (&whatever::a < &whatever::b) 这样的代码是否会受到影响,还是只需要修复即可得到预期结果? - chris
@chris:我想你可以把它解释为属于上面的引用,但我认为它并不是旨在被涵盖的。真正的意图是像我上面展示的那样,当您更改声明顺序时,程序的基本含义(例如T所指的类型)会发生变化。如果您包括成员地址(可能)随着顺序更改而更改,则会说几乎每个具有多个非静态数据成员的结构/类都存在未定义行为,我相信这并不是预期的。 - Jerry Coffin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接