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

xmh0511
  • 7,010
  • 1
  • 9
  • 36
  • 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 Jul 30 '20 at 03:42
  • @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 Jul 30 '20 at 05:23
  • 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 Jul 30 '20 at 07:56
  • @quetzalcoatl Maybe `Clang` is right, rather `GCC` is wrong. According to the first and the second quote. – xmh0511 Jul 30 '20 at 08:16
  • @JackX " explicit qualification ([namespace.qual])" **does** mean the name must be qualified. – Oliv Jul 30 '20 at 11:19
  • @Oliv what it says is **definition for the member of a namespace**. However `explicit specialization a template does not introduce a name `, So, that's not the definition for `Test` itself. Moreover, `Test` is not the name of the member. It's just a `template-id` – xmh0511 Jul 30 '20 at 12:37
  • @JackX `Test` is a member of namespace `B`. The member name is `Test`. `template struct test {...}` is not an explicit specialization, this is a definition. There is not specialization here. A definition is not a specialization! To recap 1) *members of a named namespace* => OK for `Test`: it is a member of named namespace `B`. *can also be **defined** by explicit qualification of the name being defined* => `B::Test` is the name `Test` explicitly qualified by `B::` it names member `Test` of namespace `B` and `template struct B::Test {` is a definition of the primary templa – Oliv Jul 30 '20 at 14:36
  • 1
    @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` 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 Jul 30 '20 at 15:28
  • @jackX Oh that. I thin that the last paragraph you site is just to say that in some part of the declaration and in the definition of the specialization, names are looked up from namespace B not A. A specialization is also a member of the namespace of the primary template. I think this is clearer in the C++20 standard. Imagine that you fall on such a specialization in real code as the one clang accept. How could you know that names in the definition of the specialization does not refer to tje apparently enclosing namespace? – Oliv Jul 30 '20 at 16:13
  • @Oliv You're right about the last paragraph. However you're wrong about `A specialization is also a member of the namespace of the primary template`, see [namespace.memdef#1](https://timsong-cpp.github.io/cppwp/n4659/namespace.memdef#1), whose class-head-name or enum-head-name is an **identifier** – xmh0511 Jul 31 '20 at 01:44
  • @jackX I am not sure it is that clear, I recurrently ask for that I never got an answer... Let's ask Davis Herring – Oliv Jul 31 '20 at 06:15
  • @Oliv yup. for class template, the `declarator-id` which is a `template-id` is not the member of the namespace which enclosing the primary class template, It's clear in the link I cited in the above comment. But, I'm not sure whether the explicit specialization for function template is or not? Because the standards says `whose declarator-id is an unqualified-id`, it may be `template-id`. – xmh0511 Jul 31 '20 at 06:29
  • @Oliv what Davis Herring have answered you seems to conform to the last quote in my question. – xmh0511 Jul 31 '20 at 06:34

1 Answers1

4

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

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • I wait and see. However the current quotes implies that `Clang` is right. That is, the explicit specialization could be defined in a namespace where its primary template could defined and at that point, as long as the template name could be found. – xmh0511 Jul 31 '20 at 01:40
  • @DavisHerring I have a question since a long time that makes me unable to interpret some paragraph of the standard: Should specialization (instantiated or declared) be interpreted as members of the primary template namespace when one read the standard? – Oliv Jul 31 '20 at 06:18
  • @Oliv: They belong to it for the purposes of ADL, but they’re never found by name lookup so in most respects it doesn’t matter. – Davis Herring Jul 31 '20 at 06:21
  • @DavisHerring It seems to the quote in [namespace.memdef#1](https://timsong-cpp.github.io/cppwp/n4659/namespace.memdef#1) clarifies whether a declaration is the member of the enclosing namespace or not, It's clear about `class/class template`, as long as the `class-head-name` is a `template-id`, it's not the member of the enclosing namespace. However it's unclear about explicit specialization for function template, whose `declarator-id` could be an `unqualified-id`, according to what the standard says, It sounds like specialization for function template is the member of the enclosing namespace – xmh0511 Jul 31 '20 at 06:41
  • @DavisHerring So you could answer this question: https://stackoverflow.com/questions/63105174/when-is-there-an-ub-because-the-best-overload-match-was-not-found-by-adl-at-the?noredirect=1#comment111684658_63105174 – Oliv Jul 31 '20 at 08:49
  • @DavisHerring After reading the current draft(after P1787) carefully. I still have a doubt about the example in [class#pre-example-1]. I also post the issue to [here](https://github.com/cplusplus/draft/issues/4592#issuecomment-826057602). It seems there's no convinced rule in the current draft that states why the explicit specialization definition for `A` in that example is an error. – xmh0511 Apr 25 '21 at 01:50