5
votes
namespace A{
    namespace B{
        template<typename T>
        struct Test{
        };
    }
    using namespace B;
    template<>
    struct Test<int>{};  //#1
}

int main(){

}

Consider the above code, GCC complains such code is ill-formed and Clang consider such code is well-formed. The outcome is here. At #1, it's an explicit specialization declaration for class template Test. According to this rule:
temp.expl.spec#2

An explicit specialization may be declared in any scope in which the corresponding primary template may be defined.

The primary template Test can be defined outside namespace B, as long as it obeys the following rule:
namespace.memdef#2

Members of a named namespace can also be defined outside that namespace by explicit qualification ([namespace.qual]) 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.

That is we may define the primary template Test like this:

namespace A{
    namespace B{
        template<typename T>
        struct Test;
    }
    template<typename T>
    struct B::Test{  // Test is explicit qualified by B
    }; 
}

So, we're permitted to define explicit specialization at such point. However It's unclear that It is necessary to declare such explicit specialization by using qualified-id? However an additional rule is here:
temp.expl.spec#8

A template explicit specialization is in the scope of the namespace in which the template was defined.

So Clang is wrong? How to interpret such case.

1
Short answer is that it is a bug. This is no different then defining a non-template function. Also consider the case of there being a template struct Test declared in namespace A before namespace B - which struct Test would you be defining?1201ProgramAlarm
@1201ProgramAlarm Not necessarily. The standard only says the explicit specialization may be declared in the scope where the primary template may declared. It didn't say the declarator-id of explicit specialization must be a qualified-id which contain nested-name-specifier that named enclosing namespace. So, I think it's unclear in the standard. Maybe Clang is right.xmh0511
I read the code, thought "sure, it's a bug" but then, I finally noticed using namespace B;. I wouldn't be surprised at all if it was intended behavior. I, as a user of a programming language, would expect this to work like that. Sure, that's C++, not all things are as-human-would-intuively-expect, but still..quetzalcoatl
@quetzalcoatl Maybe Clang is right, rather GCC is wrong. According to the first and the second quote.xmh0511
@Oliv I said the first code. Test is a member of B and A is the enclosing namespace of B, where the definition of Test may be defined in A, so the explicit specialization could be defined here. Test<int> is not the name of that template and it's not the definition for template Test. It's a explicit specialization. hence Clang is right.xmh0511

1 Answers

4
votes

You are correct that the existing wording is more than a little unclear. I won’t try to fathom its meaning as written, if it has one, further than you already have; I consider it all bad enough to need a complete rewrite.

The intent, however, is that this code is well-formed (as Clang says); because the explicit specialization (of a class template) must contain Test<, which might be part of a nested-name-specifier (template<> struct Test<int>::Nested<float> {};), Test is subject to a normal name lookup that follows the using-directive (among many other things). Note that this differs from [class.pre]/3 which forbids using a nested-name-specifier to redeclare a class brought in via a using-declaration. (The rules for explicit specializations and instantiations of function templates are a bit more complicated because the template argument list is optional.)

Within a few weeks, there will be a public update of my linked paper that adjusts the rules for redeclarations along these lines (in [class.pre] in this case).