Is rule 3 in section 3.3.7/1 from N3936 redundant?

2020-02-12 06:21发布

问题:

I recently answered a question dealing with a violation of draft C++14 standard: N4140 section 3.3.7 Class scope paragraph 1 rule 2 which says:

A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.

at the time rule 3 also seemed relevant and it says:

If reordering member declarations in a class yields an alternate valid program under (1) and (2), the program is ill-formed, no diagnostic is required.

My initial reaction is that rule 3 seems redundant and is really just a clarification of rule 2 and does not cover any cases not already covered. A reordering that results in a alternate valid program would also have to violate rule 2.

So is rule 3 redundant or is there some edge cases that requires both rules?

回答1:

According to Defect Report 1875: Reordering declarations in class scope rule 3 is redundant and the proposed solution is to remove rule 3, it says:

The need for rule #3 is not clear; it would seem that any otherwise-valid reordering would have to violate rule #2 in order to yield a different interpretation. Taken literally, rule #3 would also apply to simply reordering nonstatic data members with no name dependencies at all. Can it be simply removed?

and the proposed solution is:

Delete the third item of 3.3.7 [basic.scope.class] paragraph 1 and renumber the succeeding items

Although this defect report seems to confirm my initial suspicious I am left with a nagging feeling that perhaps rule 3 is bit broader after all. Section 3.3.7 includes the following example:

enum { i = 1 };

class X {
  char v[i]; // error: i refers to ::i
             // but when reevaluated is X::i
  int f() { return sizeof(c); } // OK: X::c
  char c;
  enum { i = 2 };
};

which violates both rule 2 and 3 but a small tweak:

enum { i = 1 };

class X {
  enum { i = 2 };
  char v[i];  // no longer refers to ::i 
              // but reordering can cause it to refer to ::i again

  int f() { return sizeof(c); } // OK: X::c
  char c;
};

seems to no longer violate rule 2 but sure seems to violate rule 3. I would consider this code example to be troublesome since a reordering of the members could easily cause the code to be back in violation of rule 2 but no diagnostic is required to indicate this which makes this code rather fragile.

Update

As far as I understand rule 3 does not apply to this example mentioned by Casey in the comment:

class X { int a; int b; };

because even though there is more than one valid ordering this case does not fall under both rule 1 and 2 which rule 3 requires:

alternate valid program under (1) and (2)