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


1004. Injected-class-names as arguments for template template parameters

Section: 13.8.2  [temp.local]     Status: C++11     Submitter: Jason Merrill     Date: 2009-11-19

[Voted into the WP at the March, 2011 meeting as part of paper N3262.]

The injected-class-name of a class template can be used either by itself, in which case it is a type denoting the current instantiation, or followed by a template argument list, in which case it is a template-name. It would be helpful to extend this treatment so that the injected-class-name could be used as an argument for a template template parameter:

    template <class T> struct A { };

    template <template <class> class TTP> struct B { };

    struct C: A<int> {
       B<A> b;
    };

(This is accepted by g++.)

James Widman:

It would not be so helpful when used with overloaded function templates, for example:

    template <template <class> class TTP>  void f(); // #1
    template <                 class T  >  void f(); // #2

    template <class T> struct A { };

    struct C: A<int> {
        void h(  ) {
            f<A>(); //  #1?  #2?  Substitution failure?
        }
    };

(See also issue 602.)

Proposed resolution (November, 2010) [SUPERSEDED]:

Change 13.8.2 [temp.local] paragraphs 1-5 as follows:

Like normal (non-template) classes, class templates have an injected-class-name (Clause 11 [class]). The injected-class-name can be used with or without a template-argument-list as a template-name or a type-name. When it is used without a template-argument-list, it is equivalent to the injected-class-name followed by the template-parameters of the class template enclosed in <>. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration it refers to the specified class template specialization, which could be the current specialization or another specialization. class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.

Within the scope of a class template specialization or partial specialization, when the injected-class-name is not followed by a < used as a type-name, it is equivalent to the injected-class-name template-name followed by the template-arguments of the class template specialization or partial specialization enclosed in <>. [Example:

  template<template<class> class T> class A { };
  template<class T> class Y;
  template<> class Y<int> {
    Y* p;           // meaning Y<int>
    Y<char>* q;     // meaning Y<char>
    A<Y>* a;        // meaning A<::Y>
    class B {
      template<class> friend class Y;  // meaning ::Y
    };
  };

end example]

The injected-class-name of a class template or class template specialization can be used either with or without a template-argument-list as a template-name or a type-name wherever it is in scope. [Example:

  template <class T> struct Base {
    Base* p;
  };

  template <class T> struct Derived: public Base<T> {
    typename Derived::Base* p;    // meaning Derived::Base<T>
  };

  template<class T, template<class> class U = T::template Base> struct Third { };
  Third<Base<int>> t; // OK, default argument uses injected-class-name as a template

end example]

A lookup that finds an injected-class-name (6.5.2 [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 followed by a template-argument-list 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]

When the normal name of the template (i.e., the name from the enclosing scope, not the injected-class-name) is used without a template-argument-list, it always refers to the class template itself and not a specialization of the template. [Example:...

This resolution also resolves issue 602.