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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With