Explicit instantiation of typedef, Clang vs GCC

74 views
Skip to first unread message

Johannes Schaub

unread,
Oct 7, 2016, 11:28:39 AM10/7/16
to std-dis...@isocpp.org
Given this typedef

template<typename T>
class A { };

typedef A<int> SomeInt;

GCC allows to explicitly instantiate it by using the injected class name

template class SomeInt::A;

It is clear that this is ill-formed by

"If the explicit instantiation is for a class or member class, the
elaborated-type-specifier in the declaration shall include a
simple-template-id."

However, this requirement seems ridiculous. The following appears to
satisfy it, seemingly making it valid C++. Clang still rejects it and
GCC still accepts

template<typename T> using alias = T;
template class alias<SomeInt>::A;

I am not sure whether I can make sense of the requirement, and why
Clang still rejects the code.

Richard Smith

unread,
Oct 7, 2016, 2:32:06 PM10/7/16
to std-dis...@isocpp.org
Clang is not rejecting it due to the rule you quote; enforcement of that weird rule is relaxed by default and only enabled under -pedantic. Instead, the issue is that Clang is just not expecting to be told to explicitly instantiate the injected-class-name of a class template.

I think the more interesting question is whether GCC is correct to accept "template class SomeInt::A;". [temp.local]/1 says:

"Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>."

If SomeInt::A is truly equivalent to SomeInt::A<int>, does that mean that SomeInt::A is considered to include a simple-template-id? I'd be inclined to say no, since the simple-template-id rule is clearly concerned with the syntactic form of the declaration and not the semantics, but this doesn't seem very clear.

Johannes Schaub

unread,
Oct 7, 2016, 2:48:46 PM10/7/16
to std-dis...@isocpp.org
2016-10-07 20:32 GMT+02:00 Richard Smith <ric...@metafoo.co.uk>:
> On Fri, Oct 7, 2016 at 8:28 AM, 'Johannes Schaub' via ISO C++ Standard -
> Discussion <std-dis...@isocpp.org> wrote:
>>
>> Given this typedef
>>
>> template<typename T>
>> class A { };
>>
>> typedef A<int> SomeInt;
>>
>> GCC allows to explicitly instantiate it by using the injected class name
>>
>> template class SomeInt::A;
>>
>> It is clear that this is ill-formed by
>>
>> "If the explicit instantiation is for a class or member class, the
>> elaborated-type-specifier in the declaration shall include a
>> simple-template-id."
>>
>> However, this requirement seems ridiculous. The following appears to
>> satisfy it, seemingly making it valid C++. Clang still rejects it and
>> GCC still accepts
>>
>> template<typename T> using alias = T;
>> template class alias<SomeInt>::A;
>>
>> I am not sure whether I can make sense of the requirement, and why
>> Clang still rejects the code.
>
>
> Clang is not rejecting it due to the rule you quote; enforcement of that
> weird rule is relaxed by default and only enabled under -pedantic. Instead,
> the issue is that Clang is just not expecting to be told to explicitly
> instantiate the injected-class-name of a class template.
>

Ah I see. I do not find support for that behavior of clang in the spec, though.

> I think the more interesting question is whether GCC is correct to accept
> "template class SomeInt::A;". [temp.local]/1 says:
>
> "Like normal (non-template) classes, class templates have an
> injected-class-name (Clause 9). The injected-class-name can be used as a
> template-name or a type-name. When it is used with a template-argument-list,
> as a template-argument for a template template-parameter, or as the final
> identifier in the elaborated-type-specifier of a friend class template
> declaration, it refers to the class template itself. Otherwise, it is
> equivalent to the template-name followed by the template-parameters of the
> class template enclosed in <>."
>
> If SomeInt::A is truly equivalent to SomeInt::A<int>, does that mean that
> SomeInt::A is considered to include a simple-template-id? I'd be inclined to
> say no, since the simple-template-id rule is clearly concerned with the
> syntactic form of the declaration and not the semantics, but this doesn't
> seem very clear.
>

About the ambiguity, I agree and I think that it should not be
considered to be equivalent to a simple-template-id. Equally I think
that it's not really clear. For example,
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2143
clarified indirectly that the injected class name is not considered to
be a simple-template-id even if used as a type. On the other side, I
remember that I sent in a DR about the same issue, and it was rejected
on the basis that the injected class name is equivalent to a
simple-template-id in the relevant case.

The description, "equivalent to a <non-terminal> followed by the
<non-terminals> enclosed by <tokens>", sounds rather synactic though.
So I understand that there can be different opinions with regard to
this text.

If we use the "alias" trick of above however, the question whether GCC
is correct or not is correctly answered as "correct", right? Then
there does exist a simple-template-id in the elaborate type specifier.
Reply all
Reply to author
Forward
0 new messages