Normally, typename
is used to disambiguate between cases where an identifier may refer to a type, or may refer to something else:
template
The keyword typename
is only permitted by the C++ syntax to introduce a template type parameter, or before a qualified name, i.e. something containing the ::
token.
So your #1 and #2 are ill-formed because MyClass
and T
are unqualified names, not containing any ::
.
Before a qualified name, the typename
token is:
C++17 [temp.res]/3,5,6:
When a qualified-id is intended to refer to a type that is not a member of the current instantiation and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword
typename
, forming a typename-specifier. ...A qualified name used as the name in a class-or-decltype (Clause [class.derived]) or an elaborated-type-specifier is implicitly assumed to name a type, without the use of the
typename
keyword. In a nested-name-specifier that immediately contains a nested-name-specifier that depends on a template parameter, the identifier or simple-template-id is implicitly assumed to name a type, without the use of thetypename
keyword. [Note: Thetypename
keyword is not permitted by the syntax of these constructs. - end note]If, for a given set of template arguments, a specialization of a template is instantiated that refers to a qualified-id that denotes a type or a class template, and the qualified-id refers to a member of an unknown specialization, the qualified-id shall either be prefixed by
typename
or shall be used in a context in which it implicitly names a type as described above.
So your #3 is well-formed, even though the name does not depend on a template parameter and isn't even in a template declaration.
Note C++20 will add many more contexts where typename
is optional even with a dependent name, because it's possible to unambiguously determine from the contexts that the name can only mean a type.
From cppreference
Usage:
- In a template declaration, typename can be used as an alternative to class to declare type template parameters and template template parameters (since C++17).
- Inside a declaration or a definition of a template, typename can be used to declare that a dependent name is a type.
- Inside a requirements for type requirements (since C++20)
So I would say that you have no guaranties that case 1 and case 2 will compile. As they do not fall into any of these three usage cases.
And for case 3, let's see what cppreference has to say about that:
The keyword
typename
may only be used in this way before qualified names (e.g. T::x), but the names need not be dependent.The keyword typename must only be used in template declarations and definitions and only in contexts in which dependent names can be used. This excludes explicit specialization declarations and explicit instantiation declarations.(until C++11)
The keyword typename can be used even outside of templates. (since C++11)
So as there is no template in your example, case 3 should be guarantied to work only since C++11
And indeed a test program compiled OK with g++ -std=c++11 but issued this warning without -std=c++11
warning: 'typename' occurs outside of a template [-Wc++11-extensions]