Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it a bug in clang that defines a member of a namespace without using nested-name-specifier

Tags:

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.

like image 586
xmh0511 Avatar asked Jul 30 '20 02:07

xmh0511


1 Answers

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).

like image 73
Davis Herring Avatar answered Oct 18 '22 10:10

Davis Herring