3

I was going to file a bug against GCC, but then realized that if my interpretation of the Standard is correct, it's a core language defect, not a compiler bug.

When a static data member of array type is defined outside class scope, identifiers in the array bound are looked up in class scope.

§9.4.2 [class.static.data] says "The initializer expression in the definition of a static data member is in the scope of its class (3.3.7)," but doesn't say anything about the declarator itself. It seems that this is the only name lookup context within a declarator.

§8.4.2 [dcl.array] doesn't mention the scope of the array bound, so by default the expression is evaluated in the enclosing scope, which is the namespace.

class X {
  static int const size = some_complicated_metafunction<>::value;
  static int arr[ size ];
};

// "size" should be qualified as "X::size", which is an access violation.
int X::arr[ size ] = {};

The problem is that if the array bound is not evaluated in class scope, there is no way to access private class members, and some_complicated_metafunction<> would have to be respecified. The array bound needs the same scope as the initializer, for essentially the same reason as the initializer. (Although not quite as strong, since constant expressions can always be recomputed, unlike the address of a private object.)

Am I missing something or is a DR in order?

5
  • Both size and X::size work fine in GCC 4.7. Commented Apr 8, 2012 at 11:06
  • @KerrekSB very interesting, it works with GCC 4.6.1 as well. When you try to reference X::size anywhere else, you get a compiler error, but it's OK here. Do you know what exactly is happening here? Commented Apr 8, 2012 at 11:12
  • Which compiler error? X::size is private of course. Commented Apr 8, 2012 at 11:13
  • @KerrekSB Yes, that is the reason I was going to file a bug against GCC: it works but the standard doesn't say it should. Moreover, if the identifier had different definitions at namespace and class scope, the wrong one would be chosen. Commented Apr 8, 2012 at 11:44
  • I won't argue on standardese terms, but on principle terms. When you define a method outside a class, you need name its return type and can do so even if it is private to the class. I feel that X::size here is the same. Fundamentally, the definition is part of the class itself, and just happens to be written elsewhere. Commented Apr 8, 2012 at 15:29

1 Answer 1

4

I think the array bound in a member definition is in class scope. Standard 3.3.7/1:

The following rules describe the scope of names declared in classes.

...

5) The potential scope of a declaration that extends to or past the end of a class definition also extends to the regions defined by its member definitions, even if the members are defined lexically outside the class (this includes static data member definitions, nested class definitions, member function definitions (including the member function body and any portion of the declarator part of such definitions which follows the declarator-id, including a parameter-declaration-clause and any default arguments (8.3.6). ...

Here the declarator-id is X::arr.

Sign up to request clarification or add additional context in comments.

1 Comment

Hmm, it's ambiguous whether that refers exclusively to member function definitions. But this covers many other cases, such as arguments of partial and explicit specializations of member class templates. The ambiguity is exacerbated by the unbalanced parens. I think the second left paren is supposed to be a right paren, in which case it explains the behavior nicely. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.