This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 114a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-04-18


316. Injected-class-name of template used as template template parameter

Section: 13.8.2  [temp.local]     Status: NAD     Submitter: Jason Merrill     Date: 14 Oct 2001

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.