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;, soTcan 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
Tand finds the enclosing definition ofTasX, sinceC::Thasn't been declared yet. But afterC::Thas been declared, it implies that ifT x;were to be reinterpreted, thenTwould now refer toC::Tinstead, since the class scope takes precedence over the enclosing scope.The above example is illegal. The fact that both declarations of
Tmake it refer to the same type is not relevant. The violation occurs becauseT x;would find a different declaration ofTafter the class is completely defined.The above example is legal. The declaration
using T = Y;does not change the meaning of::T, because::Twill always refer to the global declaration even thoughC::Tis there.The above example is legal. The body of
foois a complete-class context, which implies that name lookup forTis not done until after the entire class has been seen. Put another way, the declarationusing T = Y;in a sense always "precedes" the body offooso this is similar to the first example.