This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-10-26
A gcc hacker recently sent in a patch to make the compiler give an error on code like this:
template <template <typename> class T> struct A { }; template <typename U> struct B { A<B> *p; };presumably because the DR from issue 176 says that we decide whether or not B is to be treated as a template depending on whether a template-argument-list is supplied. I think this is a drafting oversight, and that B should also be treated as a template when passed as a template template parameter. The discussion in the issue list only talks about making the name usable both as a class and as a template.
John Spicer: This case was explicitly discussed and it was agreed that to use the injected name as a template template parameter you need to use the non-injected name.
A (possibly unstated) rule that I've understood about template arguments is that the form of the argument (type/nontype/template) is based only on the argument and not on the kind of template parameter. An example is that "int()" is always "function taking no arguments returning int" and never a convoluted way of saying zero.
In a similar way, we now decide whether or not something is a template based only on the form of the argument.
I think this rule is important for two kinds of cases. The first case involves explicit arguments of function templates:
template <template <typename> class T> void f(){} // #1 template <class T> void f(){} // #2 template <typename U> struct B { void g() { f<B>(); } }; int main() { B<int> b; b.g(); }
With the current rules, this uses B as a type argument to template #2.
The second case involves the use of a class template for which the template parameter list is unknown at the point where the argument list is scanned:
template <class T> void f(){} template <typename U> struct B { void g() { f< U::template X<B> >(); // what is B? } }; struct Z1 { template <class T> struct X {}; }; struct Z2 { template <template <class> class T> struct X {}; }; int main() { B<Z1> b1; b1.g(); B<Z2> b2; b2.g(); }
If B could be used as a template name we would be unable to decide how to treat B at the point that it was scanned in the template argument list.
So, I think it is not an oversight and that it should be left the way it is.
Notes from the 4/02 meeting:
It was agreed that this is Not a Defect.