I think they are considered different in this scenario:
template<class T> struct t_{ using type = T; };
Because [temp.over.link] says ( emphasis mine )
To determine whether dependent names are equivalent, only the name itself is considered, and not the result of the name search in the template context .
Since T and typename t_<T>::type differ in naming, the compiler will accept these template declarations.
Now you canβt name them both, because the resulting template instances are functionally equivalent, which leads to ambiguity. Such a program is poorly formed, no diagnostics are required * (See @Barry for an excellent answer ).
MSVC 19.00.23506 , clang 6.0.0 and gcc 8.0.0 all seem to agree with me on this (none of them give diagnostics).
Note that the compiler allows you to declare these patterns until they call, while something like this will not compile, even if the patterns are not created:
template<class U> typename t_<U>::type f(U){return {};} template<class T> typename t_<T>::type f(T){return {};}
* "If the program contains declarations of function templates, functionally equivalent but not equivalent, the program is poorly formed, no diagnostic is required."
source share