8

It is continuation of this question. I am specifically interested if the partial specialization of a member class like this:

struct FooParent {
    template <class>
    struct Bar{ };
};

struct Foo: FooParent {
    template <class T>
    struct Bar<T*> {};
};

I know this can be done inside a namespace scope:

template <class T>
struct Foo::Bar<T*>{ };

But I'm also specifically interested in in-class partial specialization at the level of derived class.

Both clang and gcc complains when encounter a former:

clang states that there is an explicit template specialization which obviously does not occur:

error: explicit specialization of 'Bar' in class scope

gcc is a little bit less verbose here and says that the specialization of the member template must be performed at a namespace scope which obviously is not a case for not derived class.

error: specialization of 'template struct FooParent::Bar' must appear at namespace scope

Is gcc right here in his error message?

Community
  • 1
  • 1
W.F.
  • 13,888
  • 2
  • 34
  • 81
  • I guess [this](http://eel.is/c++draft/temp.class.spec#5) rules on it. You cannot define primary template in the derived class, so you cannot declare a partial specialization as well. - _A class template partial specialization may be declared or redeclared in any namespace scope in which the corresponding primary template may be defined_ – skypjack Nov 18 '16 at 21:34
  • @skypjack not the case as it is about **allowing** the undesired namespace scope specialization not disallowing anything - see the [reference question](http://stackoverflow.com/questions/40656857/why-is-in-class-partial-specialization-well-formed) and discussion in comments... – W.F. Nov 18 '16 at 21:37
  • I got it as _this is allowed, thus everything else is disallowed_. You are saying instead that it is allowed, but there could be something else declared as allowed somewhere in the standard, right? So you want an explicit rule that disallows it. Did I get your goal rightly? – skypjack Nov 18 '16 at 21:43
  • @skypjack Not exactly, please see [this](http://eel.is/c++draft/temp.class.spec.mfunc#2). This suggests that it is perfectly legal to in-class partial specialization of the struct. The comment of Johannes Schaub - litb on my previous question goes even a step beyond - it suggests that the partial specialization is a template and as such can be declared wherever the template can be declared... the scope of derived class IMHO should allow to declare template, no? Am I missing something? – W.F. Nov 18 '16 at 21:46
  • Partial specializations of a class template are templates themselves, it's right. Anyway they cannot be declared wherever you want. My first comment points out where you can declare such a template. And that's where the primary template can be defined, that is not a derived class. I don't understand what make you think you can do that, honestly, but maybe I'm missing something important from your question. It seems to me that you are mixing up rules for primary templates and partial specializations, but I can be wrong of course. – skypjack Nov 18 '16 at 21:56
  • @skypjack I'm not saying they can. My question is - if they cannot then why?... I do actually cited the fragment you provided in your comment just in my previous question - that is why I thought you missed the discussion below it... but maybe you didn't... – W.F. Nov 18 '16 at 22:04
  • @skypjack maybe I am mixing them :) show me the rules and let's find out! – W.F. Nov 18 '16 at 22:06
  • Actually I've read it and that's why I added a comment instead of an answer. You've already answered it for yourself. :-) – skypjack Nov 18 '16 at 22:06
  • The rules are in the fragment you quoted. You are declaring (and contextually defining, but it's first of all a declaration) a partial specialization. You can declare it only where a definition for the primary template is allowed. That is not within a derived class. You must look for where a definition of a primary template is allowed from this point on. Partial specializations are no longer of interest for your doubt after that bullet. Do we agree on this? – skypjack Nov 18 '16 at 22:14
  • @skypjack My understanding of the fragment is a bit different but maybe you are right... I'll try to read it tomorrow once again and maybe it become nicer and clearer then :) – W.F. Nov 18 '16 at 22:22
  • 1
    I'm not a native speaker, you know. So I could be wrong as well. Anyway it looks pretty clear to me. That's also why I cannot see what's wrong in it from your point of view. Let me know tomorrow if your doubts are still there. :-) ... That said, good question: +1 - I've never tried to do such a thing before actually and never thought if it was possible or not. – skypjack Nov 18 '16 at 22:30
  • @skypjack you're right in your diagnosis. I was wrongly assuming that inheriting from class with template creates another (different) template in derived class... This is not a case though I can see it now! :) still not sure if given fragment of c++ standard is talking explicitly about that case scenario but if you compose the answer with your interpretation I'll accept the answer – W.F. Nov 19 '16 at 09:00
  • Ok, I'm doing it in a couple of hours. Not at home right now. ;-) – skypjack Nov 19 '16 at 09:10
  • @skypjack no rush ;) – W.F. Nov 19 '16 at 09:11
  • Tried to explore it a bit further. Let me know if you find weak point in the reasoning and I'll improve the answer. – skypjack Nov 19 '16 at 10:02

1 Answers1

1

I'm trying to sum up what I said in the comments to the question, as requested by the OP.


I guess [temp.class.spec]/5 is enough to reply to the question.
In particular:

A class template partial specialization may be declared or redeclared in any namespace scope in which the corresponding primary template may be defined [...].

In this case, what actually rule on it is where the primary template can be defined.
In the example, you are trying to declare (and contextually define, but it's first of all a declaration) a partial specialization in a derived class.

The short answer is: you cannot define the primary template in the derived class, so you cannot declare a partial specialization in that class as well.

If it was possible , the following would have been possible too:

struct FooParent {
    template <class>
    struct Bar;
};

struct Foo: FooParent {
    template <class T>
    struct FooParent::Bar<T*> {};
};

Or this one if you prefer:

struct Foo: FooParent {
    template <class T>
    struct Bar<T*> {};
};

Unfortunately (?) they are not allowed and this would suffice to tell you that your attempt to specialize the class template is invalid as well.

Anyway, let's consider it a bit further.
The primary template is part of the member specification of Foo (see here for further details).
Thus, the question - where can I define such a template?, quickly becomes - where can I define any other member of the class?.
Again, the answer is - not in the scope of a derived class.


I'm pretty sure that a language-lawyer would give you more direct and straightforward explanation.
I'm also pretty sure that the same language-lawyer would curse me for having mentioned the wrong sections of the standard.
Anyway, I hope the few examples above can give you a base point from which to start.

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • `template struct Foo::Bar{ };` this one is actually accepted by the compilers - not in the scope of the derived class of course but in the namespace scope where the base class was declared - this was also what misled me to the thought that it should be possible... I actually think now that the syntax should be prohibited by the compilers... – W.F. Nov 19 '16 at 10:21
  • @W.F. Why should it be prohibited? It is the same syntax you can use for an out-of-line member definition. And the nested class template is a member of the class, as mentioned in the answer. – skypjack Nov 19 '16 at 10:23
  • Because when e.g. you declare `Goo` deriving from the `FooBase` and you specializing `Goo::Bar` you are redeclaring specialization... What if `FooBase` was a template it just makes a lot of confusion and unexpected behaviour... – W.F. Nov 19 '16 at 10:25
  • To make the things straight I think you should be able to specialize it as follows: `template struct FooBase::Bar{ };` but not `template struct Foo::Bar{ };` – W.F. Nov 19 '16 at 10:28
  • @W.F. Ok, about the fact that _it makes confusion_ I can agree with you. Anyway, we are dealing with a language that allows you to do `delete this` in a member function and has an utility called `std::move` that doesn't move anything. So, confusion is a friend. :-) – skypjack Nov 19 '16 at 10:28
  • 1
    Good point :) As the programmer should avoid risky syntax it doesn't mean the language should prohibit it... This is why we need to know where are the limits of the language and I think the question (maybe not thought through very much) still may be useful :) – W.F. Nov 19 '16 at 10:35
  • You know that partial specializations can be defined inside classes? [temp.class.spec]/5 is not enough to reply to the question, I'm afraid. You should've analyzed how we can create partial specializations by instantiating a deriving class template, etc. – Columbo Nov 19 '16 at 11:02
  • @Columbo If you can give us an in-depth explanation with another answer, I'll delete mine. I was sure I missed something and I'm sure as well that you can do far better than me on this!! :-) ... Anyway, can't you define them for the same reason, that is that you can define there the primary template? I find that it still applies. Am I wrong? – skypjack Nov 19 '16 at 11:06