Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specialization of inherited nested template class

The following source code is brought from: Understanding partial specialization of inherited nested class templates

#include <type_traits>
struct Base
{
    template<class U, class _ = void> struct Inner: std::true_type {};
    template<class _> struct Inner<char, _>: std::false_type {};
};
struct Derived : Base
{
};

template<class _> struct Derived::Inner<int, _>: std::false_type {};

I had an issue about specializing inherited class, so I googled, and find out the question above. The source code in the question above compiled w/o any problem in gcc/clang, but msvc refuses to compile it, issuing C2427 (see https://msdn.microsoft.com/en-us/library/10het5hx.aspx).

Situation of the above (specialize the nested template class of a non-template class) is quite different from the situation described in https://msdn.microsoft.com/en-us/library/10het5hx.aspx (define the nested non-template class of a template class), I think.

Which one of msvc vs. gcc/clang is wrong? Or just the standard is so unclear to specify this behavior?

I hope msvc is wrong...

like image 633
Junekey Jeon Avatar asked Jul 06 '16 02:07

Junekey Jeon


People also ask

Can a member template be nested within a class template?

A member or a member template of a class template may be explicitly specialized for a given implicit instantiation of the class template, even if the member or member template is defined in the class template definition. Member or a member template may be nested within many enclosing class templates.

Why do we need template<arguments> in nested class declarations?

In such a nested declaration, some of the levels may remain unspecialized (except that it can't specialize a class member template if its enclosing class is unspecialized). For each of those levels, the declaration needs template<arguments>, because such specializations are themselves templates:

What is an explicit specialization of a template member?

Members of specializations. An explicit specialization of a static data member of a template is a definition if the declaration includes an initializer; otherwise, it is a declaration. These definitions must use braces for default initialization:

What can a static nested class inherit?

A static nested class can inherit: a static nested class that is declared in an outer class or its ancestors Recall an example from our lesson on static nested classes.


Video Answer


1 Answers

Clang and GCC are wrong, and MSVC and EDG are right to reject that partial specialization definition.

A partial specialization is itself a template, and a class template definition is syntactically constructed in terms of a class definition (in grammar terms, a class-specifier). Within such a definition, Derived::Inner<int, _> is a class-head-name, with Derived:: being a nested-name-specifier.

[9p11] in the Standard says:

If a class-head-name contains a nested-name-specifier, the class-specifier shall refer to a class that was previously declared directly in the class or namespace to which the nested-name-specifier refers, or in an element of the inline namespace set (7.3.1) of that namespace (i.e., not merely inherited or introduced by a using-declaration), and the class-specifier shall appear in a namespace enclosing the previous declaration. [...]

So, you have to use Base::Inner<int, _>.


As noted in the comments, the quote above applies to class template explicit specialization definitions as well (their grammar production also ends up using class-head-name).


The following doesn't apply directly to your example, but I found it worth mentioning.

Note that the quote above refers to class template (or explicit specialization) definitions, not declarations such as

template<class _> struct Derived::Inner<int, _>;

Syntactically, struct Derived::Inner<int, _> in there is an elaborated-type-specifier, to which the paragraph above doesn't apply. So, the Standard wording technically allows such declarations.

This doesn't seem to be an oversight: the wording above was introduced by the resolution of DR284, which includes the comment:

The sentiment was that this should be required on class definitions, but not on elaborated type specifiers in general (which are references, not declarations). [...]

The proposed resolution included elaborated-type-specifiers, but those were removed from the final wording.

However, neither MSVC nor EDG accept such declarations (and frankly I'd find it confusing if they did). The comment in the DR seems to indicate that the intent was to allow only elaborated-type-specifiers that are not also declarations, but it looks like this wasn't reflected in the wording (a Standard bug, I think).

like image 168
bogdan Avatar answered Sep 22 '22 00:09

bogdan