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

2024-04-05


176. Name injection and templates

Section: Clause 11  [class]     Status: TC1     Submitter: John Spicer     Date: 21 February 1999

There is some controversy about whether class name injection applies to class templates. If it does apply, what is injected? Is a class name injected or is the thing that is injected actually a template?

Clause 11 [class] paragraph 2 says,

The class-name is also inserted into the scope of the class itself.
In general, clause 9 applies to both classes and class templates, so I would take this to mean that class name imjection does indeed apply to class templates. One problem with this is that clause 9 uses the syntactic term class-name, which I would take to imply that the inserted name is always a class. This is clearly unacceptable for class templates as it makes the template itself unusable from with the template. For example:
    template <class T> struct A {
        A<T*> ptr;    // Invalid: A refers to a class
    };

Clearly the injected name must be usable as both a class and a class template. This kind of magic already exists in the standard. In 13.8.2 [temp.local] it says,

Within the scope of a class template, when the name of the template is neither qualified nor followed by <, it is equivalent to the name of the template followed by the template-parameters enclosed in <>.

The proposal here is that we clarify that name injection does indeed apply to class templates, and that it is the injected name that has the special property of being usable as both a class and a template name (as described in 13.8.2 [temp.local] ). This would eliminate the need for special wording regarding the qualification of the name, but would achieve the same result. This would also make this "special" name available to a derived class of a class template — something which is necessary if the benefits of class name injection are to be made uniformly available for class templates, too.

    template <class T> struct Base {
        Base* p;
        Base<T*>* p2;
        ::Base* p3;    // Error: only injected name usable as class
    };

    template <class T> struct Derived: public Base<T> {
        Base* p;    // Now okay
        Base<T*>* p2;    // Still okay
        Derived::Base* p3;    // Now okay
Note that by giving the special attribute of being usable as both a class and a template to the injected name it is now clear where this attribute can and cannot be used.

(See paper J16/99-0010 = WG21 N1187.)

Proposed resolution (10/00):

[Note: these changes depend on the resolution for issue 147.]

Replace 13.8.2 [temp.local] paragraphs 1 and 2 with the following:

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. 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, it refers to the specified class template specialization, which could be the current specialization or another specialization.

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

    template<class T> class Y;
    template<> class Y<int> {
        Y* p;          // meaning Y<int>
        Y<char>* q;    // meaning Y<char>
    };

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 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>
    };

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, 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 refers to the class template itself and not a specialization of the template. [Example:

    template <class T> class X {
        X* p;         // meaning X<T>
        X<T>* p2;
        X<int>* p3;
        ::X* p4;      // error: missing template argument list
                      // ::X does not refer to the injected-class-name
    };

end example]