`typename` keyword before non-type template parameter defined via nested templated `using` in out-of-line member definition

I hope this is a good audience.

Title seems long an convoluted, but the problem boiled down to gcc and
clang disagreeing on such code:

(This is a grokked version of code which we got during a real world
code-base evolution [if that means anything])

#include <type_traits>
#include <iostream>
#include <string>

template <typename T>
struct B {
    template <typename U>
    using nested_templated_using = U;

    template<typename U = T, nested_templated_using<U>* = nullptr >
    void f();
};

template <typename T>
template <typename U, typename B<T>::template nested_templated_using<U>* >
//                   ^ should typename be here or not?
void  B<T>::f(){ }

int main () { return 0;}

[godbolt example](Compiler Explorer)

clang requires `typename` keyword in the indicated spot, while gcc
forbids it. They error out with the same message indicating that the
out-of-line definition does not match declaration.

I've asked this question on
[stackoverflow](c++ - gcc doesn't accept out-of-line definition of member with non-type template parameter defined via nested templated using clause - Stack Overflow) but it
wasn't clear yet what is the core issue, I thought gcc misbehaves.

I got some great input by Johannes Schaub, who pointed [CWG issue
#2](C++ Standard Core Language Active Issues) and
[CWG issue #560](C++ Standard Core Language Active Issues).
They both treat about referring to the dependent types, though as the
type of return value.

My thoughts are:
1. The type of the parameter is dependent.
2. I am not sure whether the type of the parameter is "a member of the
current instantiation" as understood in
[temp.res#3]([temp.res])
3. In conjunction with [temp.res#5]([temp.res])
above renders "wrong guess" about the presence of the keyword a killer
- program is ill-formed.

I might be wrong in my toughts, and I am not sure whether, or not,
`typename` keyword usage changes for non-type template parameters.
Also, inline definition does not require the keyword.

It would be nice if someone could give authoritative answer
(preferably stepping through standard) whether:
1. clang is wrong.
2. gcc is wrong.
3. standard is unclear.

Regards,
Łukasz.

I hope this is a good audience.

Title seems long an convoluted, but the problem boiled down to gcc and
clang disagreeing on such code:

(This is a grokked version of code which we got during a real world
code-base evolution [if that means anything])

#include <type_traits>
#include <iostream>
#include <string>

template <typename T>
struct B {
    template <typename U>
    using nested_templated_using = U;

    template<typename U = T, nested_templated_using<U>* = nullptr >
    void f();
};

template <typename T>
template <typename U, typename B<T>::template nested_templated_using<U>* >
//                   ^ should typename be here or not?
void  B<T>::f(){ }

int main () { return 0;}

[godbolt example](Compiler Explorer)

clang requires `typename` keyword in the indicated spot, while gcc
forbids it. They error out with the same message indicating that the
out-of-line definition does not match declaration.

Strictly-speaking, neither is formally correct. For a type involving
template parameters, the two must be spelled with the same sequence of
tokens (though implementations are allowed to accept additional cases); see
[temp.over.link]. So the right thing is:

template <typename T>
struct B {
    template <typename U>
    using nested_templated_using = U;

    template<typename U = T, typename B<T>::template
nested_templated_using<U>* = nullptr >
    void f();
};

template <typename T>
template <typename U, typename B<T>::template nested_templated_using<U>* >
void B<T>::f(){ }

... which Clang and MSVC accept and GCC rejects. (ICC/EDG seems to reject
every variation on this.) However, the intent is to permit additional cases
where the equivalence of the two declarations can be determined using
information from the template itself (see CWG issue 2, wg21.link/cwg2),
which also permits your original example.

So we can at least conclude that GCC is wrong to reject your original
example. Presumably within the class definition it canonicalizes the type
of the template parameter to merely "U *", and is unable to match that up
against the "typename B<T>::template nested_templated_using<U> *" within
the out-of-class definition of f.

But that leaves open the question of whether the code without the
typename/template keywords is valid too. See below!

I've asked this question on

[stackoverflow](c++ - gcc doesn't accept out-of-line definition of member with non-type template parameter defined via nested templated using clause - Stack Overflow) but it
wasn't clear yet what is the core issue, I thought gcc misbehaves.

I got some great input by Johannes Schaub, who pointed [CWG issue
#2](C++ Standard Core Language Active Issues) and
[CWG issue #560](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_
active.html#560).
They both treat about referring to the dependent types, though as the
type of return value.

My thoughts are:
1. The type of the parameter is dependent.
2. I am not sure whether the type of the parameter is "a member of the
current instantiation" as understood in
[temp.res#3]([temp.res])

This is the right question. And, sadly, the standard is unclear on this
question; [temp.dep.type] says this depends on whether the name appears "in
the definition of [...] a member of a class template", but is the
template-parameter-list "in the definition" or not? The answer is by no
means obvious.

3. In conjunction with [temp.res#5]([temp.res])

Richard,

Perhaps I should clarify possible foul formatting of the code example.
The indicator for the dubious `typename` keyword was mean to land
before `B<T>::template nested_templated_using<U>*` in the out-of-line
definition. On a fixed font it did, in your reply I see a possibly
quite dramatic misalignment. Hopefully it can be seen on the properly
formatted code (e.g. in the acutal godbolt example.) Sincere
apologies.

So the original question was "whether the code without the
typename/template keywords is valid too."

Luckily you did pick up on it.

As I understand, your answer would be that gcc is wrong to reject the
code with the keyword present, and whether the code with out it should
be acceptable is not obvious.

But assuming that the template-parameter-list is "in the definition",
then shouldn't the superfluous `typename` make the code ill formed
based on [temp.res] $5:

A qualified name used as the name in a class-or-decltype 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 the typename keyword.
[ Note: The typename keyword is not permitted by the syntax of these constructs.]

I agree that CWG#2 is aimed at permitting such cases, but this note
sounds pretty strict. As I understand it, this puts presence or lack
of the keyword as mutually exclusive options for program to be
well-formed.

Or am I misunderstanding this, and this note does not apply to our case here?

Regards,
Łukasz.

Richard,

Perhaps I should clarify possible foul formatting of the code example.
The indicator for the dubious `typename` keyword was mean to land
before `B<T>::template nested_templated_using<U>*` in the out-of-line
definition. On a fixed font it did, in your reply I see a possibly
quite dramatic misalignment. Hopefully it can be seen on the properly
formatted code (e.g. in the acutal godbolt example.) Sincere
apologies.

So the original question was "whether the code without the
typename/template keywords is valid too."

Luckily you did pick up on it.

As I understand, your answer would be that gcc is wrong to reject the
code with the keyword present, and whether the code with out it should
be acceptable is not obvious.

But assuming that the template-parameter-list is "in the definition",
then shouldn't the superfluous `typename` make the code ill formed
based on [temp.res] $5:

> A qualified name used as the name in a class-or-decltype 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 the typename keyword.
> [ Note: The typename keyword is not permitted by the syntax of these
constructs.]

No. This is talking about the second typename in:

  typename A<X>::typename B::C

... and it says that B would be implicitly assumed to name a type in this
context without the use of the typename keyword, but that the above snippet
is ill-formed because 'typename' cannot appear after a :: here.

C++ allows you to redundantly use the 'typename' (and 'template')
disambiguators in any place in the grammar where they're allowed.

I agree that CWG#2 is aimed at permitting such cases, but this note