<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 5 February 2018 at 17:41, Łukasz Kucharski via cfe-dev <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Richard,<br>
<br>
Perhaps I should clarify possible foul formatting of the code example.<br>
The indicator for the dubious `typename` keyword was mean to land<br>
before `B<T>::template nested_templated_using<U>*` in the out-of-line<br>
definition. On a fixed font it did, in your reply I see a possibly<br>
quite dramatic misalignment. Hopefully it can be seen on the properly<br>
formatted code (e.g. in the acutal godbolt example.) Sincere<br>
apologies.<br>
<br>
So the original question was "whether the code without the<br>
<span class="">typename/template keywords is valid too."<br>
<br>
</span>Luckily you did pick up on it.<br>
<br>
As I understand, your answer would be that gcc is wrong to reject the<br>
code with the keyword present, and whether the code with out it should<br>
be acceptable is not obvious.<br>
<br>
But assuming that the template-parameter-list is "in the definition",<br>
then shouldn't the superfluous `typename` make the code ill formed<br>
based on [temp.res] $5:<br>
<br>
> 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.<br>
> 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.<br>
> [ Note: The typename keyword is not permitted by the syntax of these constructs.]<br></blockquote><div><br></div><div>No. This is talking about the second typename in:</div><div><br></div><div>  typename A<X>::typename B::C</div><div><br></div><div>... 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.</div><div><br></div><div>C++ allows you to redundantly use the 'typename' (and 'template') disambiguators in any place in the grammar where they're allowed.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I agree that CWG#2 is aimed at permitting such cases, but this note<br>
sounds pretty strict. As I understand it, this puts presence or lack<br>
of the keyword as mutually exclusive options for program to be<br>
well-formed.<br>
<br>
Or am I misunderstanding this, and this note does not apply to our case here?<br>
<br>
Regards,<br>
Łukasz.<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
On Tue, Feb 6, 2018 at 1:20 AM, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br>
> On 4 February 2018 at 18:40, Łukasz Kucharski via cfe-dev<br>
> <<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>> wrote:<br>
>><br>
>> I hope this is a good audience.<br>
>><br>
>> Title seems long an convoluted, but the problem boiled down to gcc and<br>
>> clang disagreeing on such code:<br>
>><br>
>> (This is a grokked version of code which we got during a real world<br>
>> code-base evolution [if that means anything])<br>
>> ```<br>
>> #include <type_traits><br>
>> #include <iostream><br>
>> #include <string><br>
>><br>
>> template <typename T><br>
>> struct B {<br>
>>     template <typename U><br>
>>     using nested_templated_using = U;<br>
>><br>
>>     template<typename U = T, nested_templated_using<U>* = nullptr ><br>
>>     void f();<br>
>> };<br>
>><br>
>> template <typename T><br>
>> template <typename U, typename B<T>::template nested_templated_using<U>* ><br>
>> //                   ^ should typename be here or not?<br>
>> void  B<T>::f(){ }<br>
>><br>
>> int main () { return 0;}<br>
>> ```<br>
>> [godbolt example](<a href="https://godbolt.org/g/yjPH1u" rel="noreferrer" target="_blank">https://godbolt.org/<wbr>g/yjPH1u</a>)<br>
>><br>
>>  clang requires `typename` keyword in the indicated spot, while gcc<br>
>> forbids it. They error out with the same message indicating that the<br>
>> out-of-line definition does not match declaration.<br>
><br>
><br>
> Strictly-speaking, neither is formally correct. For a type involving<br>
> template parameters, the two must be spelled with the same sequence of<br>
> tokens (though implementations are allowed to accept additional cases); see<br>
> [temp.over.link]. So the right thing is:<br>
><br>
> template <typename T><br>
> struct B {<br>
>     template <typename U><br>
>     using nested_templated_using = U;<br>
><br>
>     template<typename U = T, typename B<T>::template<br>
> nested_templated_using<U>* = nullptr ><br>
>     void f();<br>
> };<br>
><br>
> template <typename T><br>
> template <typename U, typename B<T>::template nested_templated_using<U>* ><br>
> void  B<T>::f(){ }<br>
><br>
> ... which Clang and MSVC accept and GCC rejects. (ICC/EDG seems to reject<br>
> every variation on this.) However, the intent is to permit additional cases<br>
> where the equivalence of the two declarations can be determined using<br>
> information from the template itself (see CWG issue 2, wg21.link/cwg2),<br>
> which also permits your original example.<br>
><br>
> So we can at least conclude that GCC is wrong to reject your original<br>
> example. Presumably within the class definition it canonicalizes the type of<br>
> the template parameter to merely "U *", and is unable to match that up<br>
> against the "typename B<T>::template nested_templated_using<U> *" within the<br>
> out-of-class definition of f.<br>
><br>
> But that leaves open the question of whether the code without the<br>
> typename/template keywords is valid too. See below!<br>
><br>
>> I've asked this question on<br>
>> [stackoverflow](<a href="https://stackoverflow.com/questions/48448353" rel="noreferrer" target="_blank">https://<wbr>stackoverflow.com/questions/<wbr>48448353</a>) but it<br>
>> wasn't clear yet what is the core issue, I thought gcc misbehaves.<br>
>><br>
>> I got some great input by Johannes Schaub, who pointed [CWG issue<br>
>> #2](<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2" rel="noreferrer" target="_blank">http://www.open-std.org/<wbr>jtc1/sc22/wg21/docs/cwg_<wbr>active.html#2</a>) and<br>
>> [CWG issue<br>
>> #560](<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#560" rel="noreferrer" target="_blank">http://www.open-std.org/<wbr>jtc1/sc22/wg21/docs/cwg_<wbr>active.html#560</a>).<br>
>> They both treat about referring to the dependent types, though as the<br>
>> type of return value.<br>
>><br>
>> My thoughts are:<br>
>> 1. The type of the parameter is dependent.<br>
>> 2. I am not sure whether the type of the parameter is "a member of the<br>
>> current instantiation" as understood in<br>
>> [temp.res#3](<a href="http://eel.is/c++draft/temp.res#3" rel="noreferrer" target="_blank">http://eel.is/c++<wbr>draft/temp.res#3</a>)<br>
><br>
><br>
> This is the right question. And, sadly, the standard is unclear on this<br>
> question; [temp.dep.type] says this depends on whether the name appears "in<br>
> the definition of [...] a member of a class template", but is the<br>
> template-parameter-list "in the definition" or not? The answer is by no<br>
> means obvious.<br>
><br>
>> 3. In conjunction with [temp.res#5](<a href="http://eel.is/c++draft/temp.res#5" rel="noreferrer" target="_blank">http://eel.is/c++<wbr>draft/temp.res#5</a>)<br>
>> above renders "wrong guess" about the presence of the keyword a killer<br>
>> - program is ill-formed.<br>
>><br>
>> I might be wrong in my toughts, and I am not sure whether, or not,<br>
>> `typename` keyword usage changes for non-type template parameters.<br>
>> Also, inline definition does not require the keyword.<br>
>><br>
>> It would be nice if someone could give authoritative answer<br>
>> (preferably stepping through standard) whether:<br>
>> 1. clang is wrong.<br>
>> 2. gcc is wrong.<br>
>> 3. standard is unclear.<br>
>><br>
>> Regards,<br>
>> Łukasz.<br>
>> ______________________________<wbr>_________________<br>
>> cfe-dev mailing list<br>
>> <a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a><br>
>> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-dev</a><br>
><br>
><br>
______________________________<wbr>_________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-dev</a><br>
</div></div></blockquote></div><br></div></div>