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

Łukasz Kucharski via cfe-dev cfe-dev at lists.llvm.org
Mon Feb 5 17:41:11 PST 2018


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.


On Tue, Feb 6, 2018 at 1:20 AM, Richard Smith <richard at metafoo.co.uk> wrote:
> On 4 February 2018 at 18:40, Łukasz Kucharski via cfe-dev
> <cfe-dev at lists.llvm.org> wrote:
>>
>> 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](https://godbolt.org/g/yjPH1u)
>>
>>  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](https://stackoverflow.com/questions/48448353) 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](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2) 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](http://eel.is/c++draft/temp.res#3)
>
>
> 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](http://eel.is/c++draft/temp.res#5)
>> 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.
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
>



More information about the cfe-dev mailing list