8
template<class T> 
T::type<int> f(){
    
}

According to [temp.names#3.4]

A < is interpreted as the delimiter of a template-argument-list if it follows a name that is not a conversion-function-id and

  • [...]
  • that is a terminal name in a using-declarator ([namespace.udecl]), in a declarator-id ([dcl.meaning]), or in a type-only context other than a nested-name-specifier ([temp.res]).

According to [temp.res#general-4.3.1], T::type<int> does satisfy the above rule(emphasized mine) due to the following rule

A qualified or unqualified name is said to be in a type-only context if it is the terminal name of

  • [...]
  • a decl-specifier of the decl-specifier-seq of a
  • [...]
  • simple-declaration or a function-definition in namespace scope,

T::type<int> is the decl-specifier of the function-definition for template function f that is in the namespace scope, hence the terminal name type is said to be in the type-only context.

Also, according to [temp.res#general-5]

A qualified-id whose terminal name is dependent and that is in a type-only context is considered to denote a type.

Hence, the symbol < in T::type<int> is interpreted as the delimiter of the template-argument-list due to [temp.names#3.4] while the qualified-id T::type<int> is considered to denote a type due to [temp.res#general-5], the example should be legal. However, it has been rejected by both Clang and GCC.

I wonder, Are both the keyword typename and template not necessary in this example compiled by future implementations?

xmh0511
  • 7,010
  • 1
  • 9
  • 36
  • Isn't the `template` keyword still needed to denote the start of a template? I think you can only omit it for inner template types, but I'd still prefer to keep it because it makes it easier to read. – Dai Aug 03 '21 at 09:14
  • @Dai I think `template` is not necessary to indicate `type` is a template-name in this case due to [temp.names#3.4]. – xmh0511 Aug 03 '21 at 09:16
  • Right, but `f` is the actual function template though. – Dai Aug 03 '21 at 09:17
  • @Dai Yes, `f` is declared to be a function template, however, [temp.res#general-4.3.1] refer to the *grammar*, it didn't say the decl-specifier of a function definition. – xmh0511 Aug 03 '21 at 09:20
  • I suspect [Where and When Do I Put the `template` and `typename` keywords?](https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords) may be illuminating for at least some of this. – WhozCraig Aug 03 '21 at 09:40
  • @WhozCraig It seems this [answer](https://stackoverflow.com/a/67250787/11796722) has a partial answer but is not complete. – xmh0511 Aug 03 '21 at 09:47

1 Answers1

4

Yes, this is the rule, and it’s correct; compilers simply haven’t implemented the (newer) template part yet. In discussing that addition, an example was brought up that illustrates the absurdity of requiring the keyword in this context:

template<typename T> struct A {
  template<typename U> struct B {
    B();
  }; 
  template<typename U> B<U> make();
};
template<typename T> template<typename U>
A<T>::B<U>::B() {} // no 'template' keyword required before 'B' here, but...
template<typename T> template<typename U>
A<T>::B<U> A<T>::make() { return {}; } // 'template' keyword required before 'B' here?

This also illustrates part of the motivation for dropping the requirement for typename in many contexts. A<T>::B might be a dependent name (if the declaration ends up being for something that’s not a member of (the primary template of) A), but that doesn’t interfere with parsing it since no expression can appear there.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • The keyword `template` is not required in `A::B::B()` due to `declarator-id` [temp.names#3.4]; The keyword `template` is not required in `A::B A::make()` is similar with the example in this question(i.e., due to [temp.res#general-4.3.1]), Right? – xmh0511 Aug 03 '21 at 09:57
  • @xmh0511: Yes, the `make` case is similar, but they’re both supposed to be via the type-only rule, since the first `B` in the constructor declaration is not the terminal name of the *declarator-id*. That rule needs to be tweaked to include *nested-name-specifier*s that are themselves in a type-only context. – Davis Herring Aug 03 '21 at 10:11
  • Ah, I just found out that the first `B` in `A::B::B` is not the terminal name of the declarator-id, I'm wrong in the above comment, it seems that there is no rule in the current draft that interpret why `template` can be omitted in this case(i.e., should be fixed to cover this case). – xmh0511 Aug 03 '21 at 10:18
  • Another confusion here is [temp.names#3.4] about `using-declarator`, according to [namespace.udecl#5], `using Test::tmp_id` shall be ill-formed. I don't know the intent here. Is that rule just make "<" always be the delimiter in a using-declarator? – xmh0511 Aug 03 '21 at 10:26
  • @xmh0511: It’s still interpreted as a template argument list there: it’s just a disallowed template argument list. The real purpose there is of course for `typename`. – Davis Herring Aug 03 '21 at 10:36
  • That is said, the `typename` could be omitted in a using-declaration for purpose. But, that using-declaration(comprise template-id) itself is ill-formed. – xmh0511 Aug 03 '21 at 10:54