c++namespaceslanguage-lawyerdefinitionredeclaration

Redeclaration in a namespace that does not enclose the original declaration


Namespace member can be defined in a namespace that encloses the declaration’s namespace:

Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration’s namespace.

void f();

namespace N { void ::f() {} }       // illegal for definition

namespace N { void ::f(); }         // what about redeclaration?

Class can be defined in a namespace that encloses the declaration’s namespace:

If a class-head-name contains a nested-name-specifier, the class-specifier shall refer to a class that was previously declared directly in the class or namespace to which the nested-name-specifier refers, or in an element of the inline namespace set (7.3.1) of that namespace (i.e., not merely inherited or introduced by a using-declaration), and the class-specifier shall appear in a namespace enclosing the previous declaration. In such cases, the nested-name-specifier of the class-head-name of the definition shall not begin with a decltype-specifier.

struct A;

namespace N { struct ::A {}; }      // illegal for definition

namespace N { struct ::A; }         // what about redeclaration?

Also we have the same rule for member function definition and static data member definition.

So my question is whether redeclaration (not definition) is legal in a namespace that does not enclose the original declaration?


Solution

  • Concerning struct ::A;, [dcl.type.elab]/1 makes your declaration ill-formed:

    If an elaborated-type-specifier is the sole constituent of a declaration, the declaration is ill-formed unless it is an explicit specialization (14.7.3), an explicit instantiation (14.7.2) or it has one of the following forms:

      class-key attribute-specifier-seqopt  identifier ;
      friend class-key ::opt identifier ;
      friend class-key ::opt simple-template-id ;
      friend class-key nested-name-specifier identifier ;
      friend class-key nested-name-specifier templateopt simple-template-id ;

    I don't see a problem in the function case; [dcl.meaning]/1 does permit it:

    When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace (7.3.1)) or to a specialization thereof; […] [ Note: If the qualifier is the global :: scope resolution operator, the declarator-id refers to a name declared in the global namespace scope. — end note ]

    However, both GCC and Clang insist that redeclarations, as definitions, must occur in an enclosing namespace.