Reputation: 7369
According to the rule:
temp.res#3
When a qualified-id is intended to refer to a type that is not a member of the current instantiation ([temp.dep.type]) and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename, forming a typename-specifier. If the qualified-id in a typename-specifier does not denote a type or a class template, the program is ill-formed.
That means, when a member of a current instantiation is used as a type-specifier it's not necessary to be prefixed by the keyword typename
.
Please consider the following code:
#include <iostream>
template<class T>
struct A{
struct B{
struct C{
A::B* p; //#5
};
B::C c; //#3
A::B::C d; //#4
};
A::B a; //#1
/*B::C b;*/ //#2
};
int main(){
}
The definition for current instantiation are: temp.dep.type#1
A name refers to the current instantiation if it is
- in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name of the class template or nested class,
- in the definition of a primary class template or a member of a primary class template, the name of the class template followed by the template argument list of the primary template (as described below) enclosed in <> (or an equivalent template alias specialization),
- in the definition of a nested class of a class template, the name of the nested class referenced as a member of the current instantiation, or
The declaration at #1
is well-formed due to the first bullet of current instantiation
. that is, at #1
, the name A
is the name of current instantiation
, similar for #3
.
#4
is well-formed, because it obeys the third bullet of current instantiation
, hence for A::B
, where B
is the name of current instantiation.
However, I can't understand why #2
is ill-formed, in other words, it require the keyword typename
, According to the first bullet, Isn't the name of the nested class be considered as a name of current instantiation?
Frankly, I don't know how to understand the first bullet. At least, I feel that the sentence is vague. Does it mean these injected-class-name
s(primary class name or nested class name) are all considered as a name of current instantiation as long as in one of the definitions listed in the sentence? #2
seems not support this interpretation.
What I can infer from the example is, The enclosing class name
in a nested class can be considered as a name of current instantiation but not the other way around. If understand the sentence in this way, It can understand why the code at #5
is well-formed.
So, how to read the first bullet correctly? Do you agree the sentence is vague?
Upvotes: 2
Views: 100
Reputation: 73186
Is a nested class name be considered as a current instantiation when it is used in a enclosing class template?
No.
However, as with many other passages of the standard, paragraph [temp.dep.type]/1.1 is indeed a mouthful:
A name refers to the current instantiation if it is
- (1.1) in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name of the class template or nested class, [...]
and we may need to break it down into the different cases to see that it does not apply to a nested-class-name when in the definition of class template where, in turn, the nested class is defined:
A name refers to the current instantiation if it is,
- in the definition of a class template, the injected-class-name of the class template ["or nested class" does not apply for this case]
- in the definition of a nested class of a class template, the injected-class-name of the class template or [the] nested class
- in the definition of a member of a class template, the injected-class-name of the class template ["or nested class" does not apply for this case]
- in the definition of a member of a nested class of a class template, the injected-class-name of the class template or [the] nested class
where I have emphasized the connection of the "if it is in the definition of a X (of a Y), the injected-class-name of the X (or [the] Y)". Noting particularly that when the definition is of a class template (when X is class template), there is no "a nested class" to refer back to at the latter part, when describing the "injected-class-name of the ...".
Conversely, there is no way interpret [temp.dep.type]/1.1 as
" in the definition of a class template, the injected-class-name of the class template or any nested class of the class template "
Thus, in your example, #2
, we are in the definition of a class template (namely A
), meaning only the name of the class template itself, namely A
, refers to the current instantiation.
Do you agree the sentence is vague?
Given the above, I would not say that it is vague (as this would imply some ambiguity, which I cannot see), but possible needlessly complex. It could arguably be clearer if [temp.dep.type]/1.1 was split into two separate paragraphs:
A name refers to the current instantiation if it is
- (1.1a) in the definition of a class template, or a member of a class template, the injected-class-name of the class template,
- (1.1b) in the definition of a nested class of a class template, or a member of a nested class of a class template, the injected-class-name of the class template or nested class, [...]
Upvotes: 2