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

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Tue Feb 6 15:10:21 PST 2018


On 5 February 2018 at 17:41, Łukasz Kucharski via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

> 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
> 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
> >
> >
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180206/b5d37b0f/attachment.html>


More information about the cfe-dev mailing list