Chapter 7.4.1 of the book C++ Primer says the following:
Ordinarily, an inner scope can redefine a name from an outer scope even if that name has already been used in the inner scope. However, in a class, if a member uses a name from an outer scope and that name is a type, then the class may not subsequently redefine that name
The word subsequently makes me think that it is only an error to redefine a type name after it has been used in the class. However, two paragraphs later it says:
Although it is an error to redefine a type name, compilers are not required to diagnose this error.
Does this mean that it is an error to redefine a type name even before it has been used in a class?
The OP writes in the comment section:
The answer is yes. It is legal to define a type name in a class that shadows a type name in an enclosing scope. What is not allowed is the following:
T
(though it need not be a type), is used inside a class, and name lookup finds some declarationD
, andT
, andT
, it now finds the new member declaration instead ofD
.Let's go over a few examples to clarify the issue.
The above example is legal because when the compiler sees
T x;
, it has already seenusing T = Y;
, soT
can only resolve toY
. There are no subsequent declarations inside the class that can change the meaning later.The above example is illegal. The compiler at first looks up
T
and finds the enclosing definition ofT
asX
, sinceC::T
hasn't been declared yet. But afterC::T
has been declared, it implies that ifT x;
were to be reinterpreted, thenT
would now refer toC::T
instead, since the class scope takes precedence over the enclosing scope.The above example is illegal. The fact that both declarations of
T
make it refer to the same type is not relevant. The violation occurs becauseT x;
would find a different declaration ofT
after the class is completely defined.The above example is legal. The declaration
using T = Y;
does not change the meaning of::T
, because::T
will always refer to the global declaration even thoughC::T
is there.The above example is legal. The body of
foo
is a complete-class context, which implies that name lookup forT
is not done until after the entire class has been seen. Put another way, the declarationusing T = Y;
in a sense always "precedes" the body offoo
so this is similar to the first example.