The meaning of the name used in the scope word combinantion


Keywords:c++ 


Question: 

I don't understand sense of the name used in.... What does it mean? For example (3.4.1/7):

A name used in the definition of a class X outside of a member function body...

Consider the following example:

class A { static const int a = 4; }

int b = A::a;

The name a after the nested-name-specifier used into the global scope or it used into the class scope?

The namespace analog is defined pretty clear in the 7.3.1/6:

The enclosing namespaces of a declaration are those namespaces in which the declaration lexically appears, except for a redeclaration of a namespace member outside its original namespace (e.g., a definition as specified in 7.3.1.2).


2 Answers: 

Disclaimer: Warning, language-laywer answer.

What is a "scope"?

Generally, I'd say that a scope is understood as the part of the program text enclosed by {} other than the initializer-brackets. TC++PLv4 p157 "A declaration introduces a name into a scope".

Declarative region

In [basic.scope.declarative]/1, we find the definition of a declarative region:

Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the same entity.

I think we can see the part after "that is" as a definition of the validity of a name.

Scope

[basic.scope.declarative]/1 continues with the definition of scope:

In general, each particular name is valid only within some possibly discontiguous portion of program text called its scope.

This only defines what the scope of a name is. In the phrases "used in global scope" or "used in the scope of the class", the term scope is used not related to a specific name. Similarly, [basic.scope.declarative]/3

The names declared by a declaration are introduced into the scope in which the declaration occurs, except [...].

Here, the term scope is also used in that second meaning, unrelated to a specific name.

Defining the second meaning of "scope"

Several language features such as block statements, namespaces and classes introduce a new scope. E.g. [stmt.block]/1

A compound statement defines a block scope.

Scope in its second meaning is used at least in three different contexts:

  • looked up in the scope of X
  • used in the scope of X
  • is in the scope of X

Looked up in the scope of X

Example: 3.4.3/1

If the nested-name-specifier of a qualified-id nominates a class, the name specified after the nested-name-specifier is looked up in the scope of the class, except for the cases listed below.

class X
{
    int m;
    void foo() { int n; }
};

decltype(X::m) v; // legal
decltype(X::n) w; // illegal

In this context, the scope of class X does not extend to any nested scopes such as member functions or nested classes.

Used in the scope of X

Example: 3.3.7/2

The name of a class member shall only be used as follows:

  • in the scope of its class (as described above) or a class derived from its class,
  • [...]
class X
{
    int m;
    void foo()
    {
        decltype(m) n;
    }
    static int o;
};
int X::o = decltype(m)();

Here, the scope of class X extends to nested scopes and other parts of the program, such as definitions of members outside of the class body.

Note that the initializers of static data members, nested classes and local classes are explicitly defined to be in the scope of wherever the static data member / class has been declared. For member functions, I can only find non-normative notes such as 9.3/5

The member function f of class X is defined in global scope; the notation X::f specifies that the function f is a member of class X and in the scope of class X.

As I understand it, this "is in the scope of" for member functions and nested/local classes says that those newly introduced scopes are nested scopes.

"Used in the scope of X" does not occur very often in the Standard. One could argue that 3.3.7/2 should be extended to nested scopes, to make "used in the scope of" consistent with "looked up in the scope of".

To be in the scope of X

Example: 8.5/13

An initializer for a static member is in the scope of the member's class.

class X
{
    static int m;
    static int n;
};

int n;
int o;

int X::m = n; // X::n
int X::n = o; // ::o

Name lookup for unqualified names searches the scopes (plural) "in the order listed in each of the respective categories" [basic.lookup.unqual]/1. For the initializers of the two static data members, the scope of class X is searched first, then any base classes, then the enclosing scope (here: the global scope), [basic.lookup.unqual]/7.

What is meant with "to be in the scope of X" seems to me that for unqualified lookup, the scopes searched are the ones that are searched for names used inside X, maybe plus access rules (initializers of static data members may access private members etc). As said above, this effectively nests scope of member functions and nested classes defined outside their enclosing class' body in the scope of that enclosing class.

Trying to define the scope of X

Not including the weird extensions of "used in the scope of X".

3.3.3 to 3.3.9 categorize various kinds of scopes of names. We can use these categories to categorize the parts of our program where names can be declared: A part of a program where names with block scope can be declared is a block scope. A part of the program where names with class scope can be declared is a class scope. We still need to differentiate different scopes of the same kind:

void foo()
{                   // begin scope A
    int a;          // 
    {               // begin scope B
        int b;      // 
        int c;      //
    }               // end scope B
    int d;          //
}                   // end scope A

The Standard calls A an outer scope of B (in name lookup). However, the scope B is not part of the scope A. Maybe something like "B is in the scope of A, but the names declared inside B are not in the scope of A". Consider:

class A
{
    int m;
    class B
    {
        int n;
    };
};

Here, name lookup "in the scope of the class A" won't find members of the nested class B with unqualified lookup. Also relevant: anonymous unions.

I think the best way to perform this separation is to look at the individual language features which can introduce a scope. For example, [stmt.block]/1 "A compound statement defines a block scope." We can then look at any part X of the program, find the closest previous language feature that introduced a scope which has not ended yet(*), take all the regions of the program where newly declared names are in the same scope (**), and call this the enclosing scope of X.

(*) not ended yet: for a block, the end of the block etc. (i.e., as specified by the language feature) Alternatively, not ended yet = where a name could have been declared that is still valid
(**) in the same scope: searching, beginning from this new declaration, the closest previous language feature that introduced a scope which has not ended yet, shall find the same part of the program

This seems to comply with what has been intended as the definition of declarative region as used in [basic.scope.declarative]/4:

Given a set of declarations in a single declarative region, each of which specifies the same unqualified name, they shall all refer to the same entity, or [... = be function overloads], or [... = various exceptions].

This, as far as I can see, contradicts the definition given in [basic.scope.declarative]/1:

int main()
{
    int x;
    {
        int x;
    }
}

Here, we have two declarations specifying the same unqualified name. The outer x as a name is valid also inside the inner {}; yet, this is a perfectly legal C++ program. I suspect that declarative region in fact shouldn't be associated with a single name.

I think it is possible to simplify this definition of scope by using the terminals { and }.



This phrase

A name used in the definition of a class X outside of a member function body...

considers all names that are used in the definition of a class that is starting from the class head and ending in the closing brace excluding names used in member functions (names used in member functions are considered in other paragraph).

For example

class B : public A
{
   int x;
   int a[i];
   C z;
   //..
};

So these names are A, x, a, i, C, z.

Take into account that though names x, a, and z are defined in the class their names can be used in other member definitions of the class.

As for your code example

class A { static const int a = 4; }

int b = A::a;

The name a after the nested-name-specifier used into the global scope or it used into the class scope?

then name a is searched in the class scope of class A but its qualified name used in the global scope to initialize variable b.

Consider another example though it has nothing common with the phrase you cited but has a relation with your code.

struct A
{
    static int a;
    static int b;
};

int A::a = 10;
int A::b = a;

Here is used name a without nested name specifier. It is one more rule how names are searched in the class scope.