Why is in-class partial specialization well-formed? - c++

According to [temp.class.spec] 5/ (emphasis mine)
A class template partial specialization may be declared or redeclared
in any namespace scope in which the corresponding primary template may
be defined
This would suggest that partial specialization (just like in case of explicit specialization) have to appear in the namespace scope. This is actually confirmed by the example below the paragraph:
template<class T> struct A {
struct C {
template<class T2> struct B { };
};
};
// partial specialization of A<T>::C::B<T2>
template<class T> template<class T2>
struct A<T>::C::B<T2*> { };
//...
A<short>::C::B<int*> absip; // uses partial specialization
On the other hand C++ Standard Core Language Active Issues No 727 example suggests that in-class partial specialization is well formed:
struct A {
template<class T> struct B;
template <class T> struct B<T*> { }; // well-formed
template <> struct B<int*> { }; // ill-formed
};
I'm sure core issues document is correct here, but cannot find appropriate reference to confirm that. Can you help me?

The intent is that it is valid—see N4090:
Following a brief discussion of DR 17557 and DR 7278 in Issaquah 2014, and based on discussion on the core-reflector91011, it seems as if Core is converging on the following rules for member templates and their specializations: Partial specializations and explicit specializations can be first
declared at either innermost-enclosing-class scope or enclosing
namespace scope (recognizing that explicitly declaring specializations
does not constitute adding members to a class and hence can be done
after the closing brace).
7 http://www.open­std.org/jtc1/sc22/wg21/docs/cwg_toc.html#727
8 http://www.open­std.org/jtc1/sc22/wg21/docs/cwg_toc.html#1755
9 http://accu.org/cgi­bin/wg21/message?wg=core&msg=24366(24033, 24290, 24309, 24368)
10 http://accu.org/cgi­bin/wg21/message?wg=core&msg=24731(24731, 24732, 24736, 24738)
11 http://accu.org/cgi­bin/wg21/message?wg=core&msg=25168 (25168­-25179)
I filed a core issue, because I feel the current wording is not clear enough; the paragraph you quoted can be interpreted to disallow in-class partial specializations.

The spec says at 14.5.2p1
A template can be declared within a class or class template; such a template is called a member template.
And at 14.5.5p2
Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization
Therefore, a class template partial specialization is a template, which is natural aswell because it still has parameters that are not fixed, therefore it denotes a "family of classes". And templates can be declared within a class or class template.

Related

C++ standard paragraph about member template specialization of unspecialized template

In the current draft of the C++ standard, the paragraph [temp.expl.spec]p.18 says:
A specialization of a member function template, member class template, or static data member template of a non-specialized class template is itself a template.
However, the above paragraph temp.expl.spec]p.17 states (my emphasis):
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. [...]
Therefore, it should be impossible to explicitly specialize a member template without specializing its enclosing class template, so [temp.expl.spec]p.18 is wrong. I highlighted the word explicitly because [temp.expl.spec]p.18 says "A specialization [...]". Specialization can have a lot of meanings, one of which could be explicit specialization.
I checked and [temp.expl.spec]p.18 appeared in the standard before [temp.expl.spec]p.17. For example, in the 1996 version of the standard [temp.expl.spec]p.18 is present while [temp.expl.spec]p.17 is not.
What is the original intended meaning of [temp.expl.spec]p.18?
Thank you.
There can be partial specialization of a member class template of a non-specialized class template.
Your point 17 prohibits full specialization of such a member; and point 18 clarifies that the partial specialization in this case is still a template.
The terminology "explicitly specialize" means fully specialize, and excludes partial specialization.
template<typename T>
struct A
{
template<typename U, typename V>
struct B
{
void f() {}
};
};
// OK: Partially specialize A<T>::B. This is a template
template<typename T>
template<typename U>
struct A<T>::B<U, int>
{
void g() {}
};

Is it legal to perform partial in-class specialization of a member template class in derived class

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

What does template's implicit specialization mean?

In the chapter N3797::14/4 [temp] (emphasis mine)
A template name has linkage (3.5). A non-member function template can
have internal linkage; any other template name shall have external
linkage. Specializations (explicit or implicit) of a template that
has internal linkage are distinct from all specializations in other
translation units.
was mentioned about implicit specialization. As far as I understand from the context, that concept is different from the template explicit specialization which has
template < > declaration
grammar. So, I'm guessing that implicit specialization has something to do with a partial class template specialization. Unfortunately, I couldn't normative reference defining the implicit specialization concept in the current working draft.
There is no normative term called "implicit specialization".
However, I believe that in this context, it means the complement of "explicit specialization": Every specialization that was not explicitly specialized by the user, in other (normative) words, instantiated specializations.
Consider that there are
Explicit specializations
Implicit instantiations
Explicit instantiations
Specializations instantiated through the latter two one could refer to as "implicit specializations".
The term isn't used much in the Standard, but we can deduce what it means from §14.5.5.3 - reproduced below - which I've broken into paragraphs (A), (B) and (C) for ease of reference (boldfacing mine):
(A) If a member template of a class template is partially specialized, the member template partial specializations are member templates of the enclosing class template; if the enclosing class template is instantiated (14.7.1, 14.7.2), a declaration for every member template partial specialization is also instantiated as part of creating the members of the class template specialization.
(B) If the primary member template is explicitly specialized for a given (implicit) specialization of the enclosing class template, the partial specializations of the member template are ignored for this specialization of the enclosing class template.
(C) If a partial specialization of the member template is explicitly specialized for a given (implicit) specialization of the enclosing class template, the primary member template and its other partial specializations are still considered for this specialization of the enclosing class template. [ Example:
template<class T> struct A {
template<class T2> struct B {}; // #1
template<class T2> struct B<T2*> {}; // #2
};
template<> template<class T2> struct A<short>::B {}; // #3
A<char>::B<int*> abcip; // uses #2
A<short>::B<int*> absip; // uses #3
A<char>::B<int> abci; // uses #1
-- end example]
Repeating (B) with my cross-references to the example in parentheses:
"if the primary member template (i.e. #1) is explicitly specialised (as at #3) for a given (implicit) specialisation of the enclosing class template (A), the partial specialisations of the member template (#2) are ignored for this specialisation of the enclosing class template".
We see the specialisation at #3 results in the ignoring of #2 for absip;. We can therefore conclude that the following line...
template<> template<class T2> struct A<short>::B {}; // #3
...performs an implicit specialisation of the enclosing class template, namely A<short>.
So, implicit specialisation is when specialisation of a member function implicitly involves specialisation of the class template that it's a member of. Put another way, the class template A didn't require a separate earlier specialisation for short before the member template at #1 was specialised, because it could be specialised implicitly.

Where to declare partial specializations of class member templates?

Here on stackoverflow I've found several comments (see for example the comment by jrok on this question) stating that partial specializations of class member templates are allowed at non-namespace scope (in contrast to explicit specializations) like in the example below:
class A {
template <class T, class U>
class B {};
template <class U>
class B<void, U> {};
};
Also, this example compiles just fine with both gcc and clang. However in the c++03 standard text I can only find 14.5.4 [temp.class.spec] §6 (or 14.5.5 §5 in c++11) about this issue:
A class template partial specialization may be declared or redeclared in any namespace scope in which its definition may be defined (14.5.1 and 14.5.2).
Along with the following example:
template<class T> struct A {
class C {
template<class T2> struct B { };
};
};
// partial specialization of A<T>::C::B<T2>
template<class T> template<class T2>
struct A<T>::C::B<T2*> { };
So, how about class template partial specializations at non-namespace scope? Are they allowed by the standard? And where can I find the relevant text?
Specifically, is my example valid (and would it still be valid if the enclosing class would be a template)? If not, are current compilers wrong to compile my example as stated above?
This seems to be a bit confusing, as I agree the paragraph you quoted seems to disallow partial specializations inside class definitions. However, there's [temp.class.spec.mfunc]/2:
If a member template of a class template is partially specialized, the
member template partial specializations are member templates of the
enclosing class template; [...] [Example:
template<class T> struct A {
template<class T2> struct B {}; // #1
template<class T2> struct B<T2*> {}; // #2
};
template<> template<class T2> struct A<short>::B {}; // #3
A<char>::B<int*> abcip; // uses #2
A<short>::B<int*> absip; // uses #3
A<char>::B<int> abci; // uses #1
— end example ]
IMHO this isn't very explicit; it doesn't allow partial specialization inside the class definition but rather (to me, seems to) specifies how member template specializations are treated.
Also see the Core Language Issue 708 and EWG Issue 41.

Accessing template parameters of the member templates

My first code fragment compiles and works fine:
template <class x> struct B1
{
template <class x> struct B2 { int getX() { return(16); } };
template <class x> struct B2<x*> { int getX() { return(20); } };
};
void main(int argc, char* argv[])
{
B1<int>::B2<int> a1;
B1<int>::B2<int*> a2;
printf("a1=%d, a2=%d.\r\n", a1.getX(), a2.getX());
}
Note that the name of template param is x in both templates and this is not confusing the compiler. The second example fails with the compiler crash (MSVC 2008), i.e. without giving any syntax error:
template <class x> struct B1
{
template <class x> struct B2 { int getX() { return(16); } };
template <class x> struct B2<x*>;
};
template <class x> template <class x>
struct B1<x>::B2<x*>
{
int getX() { return(3); }
};
My question is not on how to fix this example, this is obvious.
I looked in the standard (C++2003) on the rules of accessing params of template headers and I cannot find anything relevant. Maybe I am missing something.
While processing B1<x>, should compiler consider only params from the first template header? More likely yes. Then while processing B2<x>, should it consider both? More complex case is especially interesting when params of B1/B2 contain qualified identifiers themselves and these identifiers want to access params of the template header. For simplicity I am not giving the full example for this.
If anybody came across this and can comment or know some artickles/books, YouTube videos, etc, I would love to hear this.
UPDATE: I just tried the following with MSVC:
template <class x> struct B1
{
x qq1;
struct B2
{
int x;
};
};
This compiles and works as expected. I also tried an exe that accesses the inner data field x. This shows that MS compiler implemented hiding template params in the inner scopes. For me this is logical even if this does not comply with the standard.
Although the question has been considered answered by the comments, I'll provide some further details below. Note that my answer is based on C++11 (ISO/IEC 14882-2011) only.
Part 1: Can a template parameter be re-used as template-parameter of a nested member template?
There are two key statements in the standard about the status of template parameters (specifically, type-parameters – which are the only kind relevant to the question). The first statement describes them as having the same status as typedef-names:
(§14.1/3) A type-parameter whose identifier does not follow an ellipsis defines its identifier to be a typedef-name (if declared with class or typename) or template-name (if declared with template) in the scope of the template declaration. [...]
And regarding the possible redeclaration of typedef-names, we have:
(§7.1.3/6) In a given scope, a typedef specifier shall not be used to redefine the name of any type declared in that scope to refer to a different type. [...]
(Remark: The rule above seems to apply to the use of typedef specifiers only, although alias declarations (§7.1.3/2) and template parameter declarations (§14.1/3) can be used to declare typedef-names as well. That is, the rule above does not explicitly rule out the use of an alias declaration or indeed a template parameter to redeclare a typedef-name within the same scope, although that is clearly the intended meaning. The wording should be "no typedef-name declaration shall be used" instead of "a typedef specifier shall not be used".)
What it means is that you cannot do this:
{
typedef int T;
typedef float T;
}
because the second declaration occurs in the same scope in which T was originally declared. However, this:
{
typedef int T;
{
typedef float T;
}
}
is perfectly legally according to the rule above, because the second declaration is in a block scope which (although the first T is still valid there) is not the scope in which T was originally declared.
Due to §14.1/3 quoted above, we must assume that the rule applies to template parameter declarations as well, hence something like
template <typename X> template <typename X>
struct Outer<X>::Inner<X> {
};
is illegal even on the simple basis that it implies the declaration of the same typedef-name twice within the same scope.
However, in a case like
template <typename X>
struct Outer {
template <typename X>
struct Inner {
};
};
one may argue that the second declaration of template <typename X> applies to a nested scope. Fortunately, the standard does provide the following second statement about the status of template parameters:
(§14.6.1/6) A template-parameter shall not be redeclared within its scope (including nested scopes). A template-parameter shall not have the same name as the template name.
[Example:
template<class T, int i> class Y {
int T; // error: template-parameter redeclared
void f() {
char T; // error: template-parameter redeclared
}
};
template<class X> class X; // error: template-parameter redeclared
— end example ]
As clearly stated, the no-redeclaration rule that applies to any typedef-name within the declaration scope, applies to nested scopes as well in the case of template parameters.
Here is an example to motivate why I think that rule is actually useful, too. Consider:
template <typename T1>
struct Outer
{
static const int outerID = 5;
template <typename T2>
struct Inner
{
int id1() { return Outer<T1>::outerID; }
int id2() { return Outer::outerID; }
int id3() { return outerID; }
};
};
The three functions of the inner template all refer to the same static member of the outer class, but in three different ways. id2() and id3() do this because §14.6.2.1/4 requires Outer::outerID and outerID to be interpreted as referring to the current instantiation, which is Outer<T1>::outerID.
If we now replace the template parameter of the inner template with T1, the same as for the outer template, the meaning of id1() would change (because Outer<T1> would now refer to whatever the definition of T1 in the inner template is), but id2() and id3() would – most naturally – still refer to the current instantiation of the template outerID belongs to. Therefore, id1() may return a different value than id2() and id3(), which would be most awkward.
Part 2: In a partial specialization of a member template, can template parameters of the member be used as template arguments of the enclosing class, and vice versa?
Another problem addressed by the question is whether in a specialization or outside-of-class definition of a member template, such as
template <typename A> template <typename B>
struct Outer<A>::Inner<B> {
// ...
};
the template argument list of the outer template (i.e. <A> in this case) could make use of parameters defined for the inner template (i.e. B in this case), and vice versa.
Let's first consider the special case given in the question, where the two parameters are identical:
template <typename A> template <typename A>
struct Outer<A>::Inner<A> {
// ...
};
Although we have ruled this out in Part 1 already due to the re-declaration problem, we can still consider the intended meaning of this syntax, which is: Define an explicit specialization of the inner class template, in which the template argument is assumed to be same as for the outer template. The syntactically correct way to write that is
template <typename A> template <>
struct Outer<A>::Inner<A> {
// ...
};
i.e. the second parameter list would be empty. Unfortunately, this would amount to an explicit specialization of a member template, which is illegal unless the enclosing template is also explicitly specialised (§14.7.3/16).
However, if we consider a partial, rather than an explicit specialization of a member template with two or more parameters, the declaration becomes legal:
// Primary declaration
template <typename A>
struct Outer {
template <typename A, typename B>
struct Inner {
// ...
};
};
// Partial specialization of member template
template <typename A> template <typename B>
struct Outer<A>::Inner<B,A> {
// ...
};
We have now used the template argument A of the enclosing template as specialised second argument for the inner template as well. Any instantiation of the template that uses the same data type for the template argument of the outer class as well as the second template argument of the inner class, e.g.
Outer<int>::Inner<float,int> myvar;
will instantiate the specialization defined above.
Hence, using template parameters of an enclosing class in the template argument list of a member template is without problems, and the reason is that by the time Inner<B,A> is evaluated, A already has the status of a typedef-name defined at the scope level of Outer.
But doing it reversely, e.g.
template <typename A> template <typename B>
struct Outer<B>::Inner<B,A> {
// ...
};
will not work, because B is a typedef-name of the Inner scope only. The Standard states:
(§14.5.2/1) [...] A member template of a class template that is defined outside of its class template definition shall be specified with the template-parameters of the class template followed by the template-parameters of the member template.
[Example:
template<class T> struct string {
template<class T2> int compare(const T2&);
template<class T2> string(const string<T2>& s) { /∗ ... ∗/ }
};
template<class T> template<class T2> int string<T>::compare(const T2& s) {
}
— end example ]
I interpret this to mean that the two template parameter lists (one followed by the other) are kept separately, not considered as one combined list of template parameters. Hence in
template <typename A> template <typename B>
struct Outer<B>::Inner<B,A>
the interpretation of Outer<B> cannot make use of the second template parameter list, and B will be undefined, whereas in the previous case
template <typename A> template <typename B>
struct Outer<A>::Inner<B,A>
the interpretation of Inner<B,A> is possible because A has the status of a typedef-name declared in a scope that Inner is part of, i.e. it will be successfully interpreted as Inner<B,Outer::A>, which in turn is the same as Inner<B,Outer<A>::A>.