In the following cases, the injected-class-name is treated as a template-name of the class template itself:
- it is followed by <
- it is used as a template argument that corresponds to a template template parameter
- it is the final identifier in the elaborated class specifier of a friend class template declaration.
So I tried to examine all 3 cases (additionally in context of base ambiguity though I think it shouldn't matter here).
The first case seems simple.
The question is - why don't commented out examples work? They don't on both GCC & Clang so I don't think it's an implementation issue
template <template <class> class> struct A;
template <class T> struct Base {};
template <class T> struct Derived: Base<int>, Base<char>
{
// #1
typename Derived::Base<double> d;
// #2
// using a = A<Base>;
using a = A<Derived::template Base>;
// #3
template<class U1>
friend struct Base;
// template<class U>
// friend struct Derived::template Base;
};
Are the rules above only for template itself, not for bases? If so, what are rules for bases, especially for the last 2 of the cases?
The relevant rule here is [temp.local]/4:
A lookup that finds an injected-class-name ([class.member.lookup]) can result in an ambiguity in certain cases (for example, if it is found in more than one base class). If all of the injected-class-names that are found refer to specializations of the same class template, and if the name is used as a template-name, the reference refers to the class template itself and not a specialization thereof, and is not ambiguous. [ Example:
template <class T> struct Base { }; template <class T> struct Derived: Base<int>, Base<char> { typename Derived::Base b; // error: ambiguous typename Derived::Base<double> d; // OK };
— end example ]
Which I think means that this is a gcc and a clang bug. In:
using a = A<Base>;
All of the injected-class-names that are found do refer to specializations of the same class template (Base<T>
) and the name is used as a template-name (because it's a template argument for a template template parameter), so this should just refer to the class template itself and not be ambiguous.