14 Templates [temp]

14.6 Name resolution [temp.res]

14.6.2 Dependent names [temp.dep]

14.6.2.1 Dependent types [temp.dep.type]

A name refers to the current instantiation if it is

  • in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name (Clause [class]) of the class template or nested class,

  • in the definition of a primary class template or a member of a primary class template, the name of the class template followed by the template argument list of the primary template (as described below) enclosed in <> (or an equivalent template alias specialization),

  • in the definition of a nested class of a class template, the name of the nested class referenced as a member of the current instantiation, or

  • in the definition of a partial specialization or a member of a partial specialization, the name of the class template followed by the template argument list of the partial specialization enclosed in <> (or an equivalent template alias specialization). If the nth template parameter is a parameter pack, the nth template argument is a pack expansion ([temp.variadic]) whose pattern is the name of the parameter pack.

The template argument list of a primary template is a template argument list in which the nth template argument has the value of the nth template parameter of the class template. If the nth template parameter is a template parameter pack ([temp.variadic]), the nth template argument is a pack expansion ([temp.variadic]) whose pattern is the name of the template parameter pack.

A template argument that is equivalent to a template parameter (i.e., has the same constant value or the same type as the template parameter) can be used in place of that template parameter in a reference to the current instantiation. In the case of a non-type template argument, the argument must have been given the value of the template parameter and not an expression in which the template parameter appears as a subexpression. [ Example:

template <class T> class A {
  A* p1;                        // A is the current instantiation
  A<T>* p2;                     // A<T> is the current instantiation
  A<T*> p3;                     // A<T*> is not the current instantiation
  ::A<T>* p4;                   // ::A<T> is the current instantiation
  class B {
    B* p1;                      // B is the current instantiation
    A<T>::B* p2;                // A<T>::B is the current instantiation
    typename A<T*>::B* p3;      // A<T*>::B is not the
                                // current instantiation
  };
};

template <class T> class A<T*> {
  A<T*>* p1;                    // A<T*> is the current instantiation
  A<T>* p2;                     // A<T> is not the current instantiation
};

template <class T1, class T2, int I> struct B {
  B<T1, T2, I>* b1;             // refers to the current instantiation
  B<T2, T1, I>* b2;             // not the current instantiation
  typedef T1 my_T1;
  static const int my_I = I;
  static const int my_I2 = I+0;
  static const int my_I3 = my_I;
  B<my_T1, T2, my_I>* b3;       // refers to the current instantiation
  B<my_T1, T2, my_I2>* b4;      // not the current instantiation
  B<my_T1, T2, my_I3>* b5;      // refers to the current instantiation
};

 — end example ]

A name is a member of the current instantiation if it is

  • An unqualified name that, when looked up, refers to at least one member of the current instantiation or a non-dependent base class thereof. [ Note: This can only occur when looking up a name in a scope enclosed by the definition of a class template.  — end note ]

  • A qualified-id in which the nested-name-specifier refers to the current instantiation and that, when looked up, refers to at least one member of the current instantiation or a non-dependent base class thereof. [ Note: if no such member is found, and the current instantiation has any dependent base classes, then the qualified-id is a member of an unknown specialization; see below.  — end note ]

  • An id-expression denoting the member in a class member access expression ([expr.ref]) for which the type of the object expression is the current instantiation, and the id-expression, when looked up ([basic.lookup.classref]), refers to at least one member of the current instantiation or a non-dependent base class thereof. [ Note: if no such member is found, and the current instantiation has any dependent base classes, then the id-expression is a member of an unknown specialization; see below.  — end note ]

Example:

template <class T> class A {
  static const int i = 5;
  int n1[i];        // i refers to a member of the current instantiation
  int n2[A::i];     // A::i refers to a member of the current instantiation
  int n3[A<T>::i];  // A<T>::i refers to a member of the current instantiation
  int f();
};

template <class T> int A<T>::f() {
  return i;         // i refers to a member of the current instantiation
}

 — end example ]

A name is a member of an unknown specialization if it is

  • A qualified-id in which the nested-name-specifier names a dependent type that is not the current instantiation.

  • A qualified-id in which the nested-name-specifier refers to the current instantiation, the current instantiation has at least one dependent base class, and name lookup of the qualified-id does not find any member of the current instantiation or a non-dependent base class thereof.

  • An id-expression denoting the member in a class member access expression ([expr.ref]) in which either

    • the type of the object expression is the current instantiation, the current instantiation has at least one dependent base class, and name lookup of the id-expression does not find a member of the current instantiation or a non-dependent base class thereof; or

    • the type of the object expression is dependent and is not the current instantiation.

If a qualified-id in which the nested-name-specifier refers to the current instantiation is not a member of the current instantiation or a member of an unknown specialization, the program is ill-formed even if the template containing the qualified-id is not instantiated; no diagnostic required. Similarly, if the id-expression in a class member access expression for which the type of the object expression is the current instantiation does not refer to a member of the current instantiation or a member of an unknown specialization, the program is ill-formed even if the template containing the member access expression is not instantiated; no diagnostic required. [ Example:

template<class T> class A {
  typedef int type;
  void f() {
    A<T>::type i;           // OK: refers to a member of the current instantiation
    typename A<T>::other j; // error: neither a member of the current instantiation nor
                            // a member of an unknown specialization
  }
};

 — end example ]

If, for a given set of template arguments, a specialization of a template is instantiated that refers to a member of the current instantiation with a qualified-id or class member access expression, the name in the qualified-id or class member access expression is looked up in the template instantiation context. If the result of this lookup differs from the result of name lookup in the template definition context, name lookup is ambiguous. [ Note: the result of name lookup differs only when the member of the current instantiation was found in a non-dependent base class of the current instantiation and a member with the same name is also introduced by the substitution for a dependent base class of the current instantiation.  — end note ]

A type is dependent if it is

  • a template parameter,

  • a member of an unknown specialization,

  • a nested class or enumeration that is a member of the current instantiation,

  • a cv-qualified type where the cv-unqualified type is dependent,

  • a compound type constructed from any dependent type,

  • an array type constructed from any dependent type or whose size is specified by a constant expression that is value-dependent,

  • a simple-template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent, or

  • denoted by decltype(expression), where expression is type-dependent ([temp.dep.expr]).

Note: Because typedefs do not introduce new types, but instead simply refer to other types, a name that refers to a typedef that is a member of the current instantiation is dependent only if the type referred to is dependent.  — end note ]