[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
Mon Feb 5 16:20:45 PST 2018


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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20180205/e924c9ab/attachment.html>


More information about the cfe-dev mailing list