[temp.res] (original) (raw)

13 Templates [temp]

13.8 Name resolution [temp.res]

13.8.1 General [temp.res.general]

A name that appears in a declaration D of a template T is looked up from where it appears in an unspecified declaration of Tthat either is D itself or is reachable from D and from which no other declaration of Tthat contains the usage of the name is reachable.

If the name is dependent (as specified in [temp.dep]), it is looked up for each specialization (after substitution) because the lookup depends on a template parameter.

[Note 1:

Some dependent names are also looked up during parsing to determine that they are dependent or to interpret following < tokens.

Uses of other names might be type-dependent or value-dependent ([temp.dep.expr], [temp.dep.constexpr]).

A using-declarator is never dependent in a specialization and is therefore replaced during lookup for that specialization ([basic.lookup]).

— _end note_]

[Example 1: struct A { operator int(); };template<class B, class T> struct D : B { T get() { return operator T(); } };int f(D<A, int> d) { return d.get(); } — _end example_]

[Example 2: void f(char);template<class T> void g(T t) { f(1); f(T(1)); f(t); dd++; } enum E { e };void f(E);double dd;void h() { g(e); g('a'); } — _end example_]

[Example 3: struct A { struct B { };int a;int Y;};int a;template<class T> struct Y : T { struct B { }; B b; void f(int i) { a = i; } Y* p; }; Y<A> ya;

The members A​::​B, A​::​a, and A​::​Yof the template argument Ado not affect the binding of names in Y<A>.

— _end example_]

If the validity or meaning of the program would be changed by considering a default argument or default template argument introduced in a declaration that is reachable from the point of instantiation of a specialization ([temp.point]) but is not found by lookup for the specialization, the program is ill-formed, no diagnostic required.

[Note 2:

The usual qualified name lookup ([basic.lookup.qual]) applies even in the presence of typename.

— _end note_]

[Example 4: struct A { struct X { };int X;};struct B { struct X { };};template<class T> void f(T t) { typename T::X x;} void foo() { A a; B b; f(b); f(a); } — _end example_]

A qualified or unqualified name is said to be in a type-only contextif it is the terminal name of

[Example 5: template<class T> T::R f(); template<class T> void f(T::R); template<class T> struct S { using Ptr = PtrTraits<T>::Ptr; T::R f(T::P p) { return static_cast<T::R>(p); } auto g() -> S<T*>::Ptr; };template<typename T> void f() { void (*pf)(T::X); void g(T::X); } — _end example_]

A qualified-idwhose terminal name is dependent and that is in a type-only context is considered to denote a type.

[Example 6: template <class T> void f(int i) { T::x * i; } struct Foo { typedef int x;};struct Bar { static int const x = 5;};int main() { f<Bar>(1); f<Foo>(1); } — _end example_]

The validity of a templated entity may be checked prior to any instantiation.

[Note 3:

Knowing which names are type names allows the syntax of every template to be checked in this way.

— _end note_]

The program is ill-formed, no diagnostic required, if

[Note 4:

This can happen in situations including the following:

— _end note_]

[Note 5:

If a template is instantiated, errors will be diagnosed according to the other rules in this document.

Exactly when these errors are diagnosed is a quality of implementation issue.

— _end note_]

[Example 7: int j;template<class T> class X { void f(T t, int i, char* p) { t = i; p = i; p = j; X<T>::g(t); X<T>::h(); } void g(T t) { +; } };template<class... T> struct A { void operator++(int, T... t); };template<class... T> union X : T... { }; template<class... T> struct A : T..., T... { }; — _end example_]

13.8.2 Locally declared names [temp.local]

Like normal (non-template) classes, class templates have an injected-class-name ([class.pre]).

When the injected-class-name of a class template specialization or partial specialization is used as a type-name, it is equivalent to the template-name followed by thetemplate-argument_s_of the class template specialization or partial specialization enclosed in<>.

[Example 1: template<template<class> class T> class A { };template<class T> class Y;template<> class Y<int> { Y* p; Y<char>* q; A<Y>* a; class B { template<class> friend class Y; };}; — _end example_]

The injected-class-name of a class template or class template specialization can be used as either a template-name or a type-namewherever it is named.

[Example 2: template <class T> struct Base { Base* p;};template <class T> struct Derived: public Base<T> { typename Derived::Base* p; };template<class T, template<class> class U = T::Base> struct Third { }; Third<Derived<int> > t; — _end example_]

A lookup that finds an injected-class-name ([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 used as a template-name, the reference refers to the class template itself and not a specialization thereof, and is not ambiguous.

[Example 3: template <class T> struct Base { };template <class T> struct Derived: Base<int>, Base<char> { typename Derived::Base b; typename Derived::Base<double> d; }; — _end example_]

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

[Example 4: template<class T> class X { X* p; X<T>* p2; X<int>* p3;::X* p4; }; — _end example_]

The name of a template parameter shall not be bound to any following declaration whose locus is contained by the scope to which the template parameter belongs.

[Example 5: template<class T, int i> class Y { int T; void f() { char T; } friend void T(); };template<class X> class X; — _end example_]

Unqualified name lookup considers the template parameter scope of a template-declarationimmediately after the outermost scope associated with the template declared (even if its parent scope does not contain the template-parameter-list).

[Note 1:

The scope of a class template, including its non-dependent base classes ([temp.dep.type], [class.member.lookup]), is searched before its template parameter scope.

— _end note_]

[Example 6: struct B { };namespace N { typedef void V;template<class T> struct A : B { typedef void C;void f();template<class U> void g(U);};} template<class V> void N::A<V>::f() { V v; } template<class B> template<class C> void N::A<B>::g(C) { B b; C c; } — _end example_]

13.8.3 Dependent names [temp.dep]

13.8.3.1 General [temp.dep.general]

Inside a template, some constructs have semantics which may differ from one instantiation to another.

Such a constructdependson the template parameters.

In particular, types and expressions may depend on the type and/or value of template parameters (as determined by the template arguments) and this determines the context for name lookup for certain names.

An expression may betype-dependent(that is, its type may depend on a template parameter) orvalue-dependent(that is, its value when evaluated as a constant expression ([expr.const]) may depend on a template parameter) as described below.

[Note 1:

Such names are looked up only at the point of the template instantiation ([temp.point]) in both the context of the template definition and the context of the point of instantiation ([temp.dep.candidate]).

— _end note_]

[Example 1: template<class T> struct X : B<T> { typename T::A* pa;void f(B<T>* pb) { static int i = B<T>::i; pb->j++;} };

The base class nameB<T>, the type nameT​::​A, the namesB<T>​::​iandpb->jexplicitly depend on thetemplate-parameter.

— _end example_]

13.8.3.2 Dependent types [temp.dep.type]

A name or template-id refers to thecurrent instantiationif it is

A template argument that is equivalent to a template parameter can be used in place of that template parameter in a reference to the current instantiation.

A template argument is equivalent to a type template parameter if it denotes the same type.

A template argument is equivalent to a constant template parameter if it is an identifier that names a variable that is equivalent to the template parameter.

A variable is equivalent to a template parameter if

[Note 1:

Using a parenthesized variable name breaks the equivalence.

— _end note_]

[Example 1: template <class T> class A { A* p1; A<T>* p2; A<T*> p3; ::A<T>* p4; class B { B* p1; A<T>::B* p2; typename A<T*>::B* p3; };};template <class T> class A<T*> { A<T*>* p1; A<T>* p2; };template <class T1, class T2, int I> struct B { B<T1, T2, I>* b1; B<T2, T1, I>* b2; typedef T1 my_T1;static const int my_I = I;static const int my_I2 = I+0;static const int my_I3 = my_I;static const long my_I4 = I;static const int my_I5 = (I); B<my_T1, T2, my_I>* b3; B<my_T1, T2, my_I2>* b4; B<my_T1, T2, my_I3>* b5; B<my_T1, T2, my_I4>* b6; B<my_T1, T2, my_I5>* b7; }; — _end example_]

A dependent base class is a base class that is a dependent type and is not the current instantiation.

[Note 2:

A base class can be the current instantiation in the case of a nested class naming an enclosing class as a base.

[Example 2: template<class T> struct A { typedef int M;struct B { typedef void M;struct C;};};template<class T> struct A<T>::B::C : A<T> { M m; }; — _end example_]

— _end note_]

A qualified ([basic.lookup.qual]) or unqualified name is amember of the current instantiationif

[Example 3: template <class T> class A { static const int i = 5;int n1[i]; int n2[A::i]; int n3[A<T>::i]; int f();};template <class T> int A<T>::f() { return i; } — _end example_]

A qualified or unqualified name names a dependent member of the current instantiation if it is a member of the current instantiation that, when looked up, refers to at least one member declaration (including a using-declarator whose terminal name is dependent) of a class that is the current instantiation.

A qualified name ([basic.lookup.qual]) is dependent if

[Example 4: struct A { using B = int; A f();};struct C : A {};template<class T> void g(T t) { decltype(t.A::f())::B i; } template void g(C); — _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 name, the name 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.

[Example 5: struct A { int m;};struct B { int m;};template<typename T> struct C : A, T { int f() { return this->m; } int g() { return m; } };template int C<B>::f(); template int C<B>::g(); — _end example_]

An initializer is dependent if any constituent expression ([intro.execution]) of the initializer is type-dependent.

A placeholder type ([dcl.spec.auto.general]) is dependent if it designates a type deduced from a dependent initializer.

[Example 6: template<class T, class V> struct S { S(T); };template<class U> struct A { template<class T> using X = S<T, U>;template<class T> using Y = S<T, int>;void f() { new X(1); new Y(1); } }; — _end example_]

A type is dependent if it is

[Note 3:

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_]

13.8.3.3 Type-dependent expressions [temp.dep.expr]

Except as described below, an expression is type-dependent if any subexpression is type-dependent.

An id-expression is type-dependent if it is a template-id that is not a concept-id and is dependent; or if its terminal name is

or if it names a dependent member of the current instantiation that is a static data member of type “array of unknown bound of T” for some T ([temp.static]).

Expressions of the following forms are never type-dependent (because the type of the expression cannot be dependent):

A class member access expression is type-dependent if the terminal name of its id-expression, if any, is dependent or the expression refers to a member of the current instantiation and the type of the referenced member is dependent.

[Note 2:

In an expression of the formx.yorxp->ythe type of the expression is usually the type of the memberyof the class ofx(or the class pointed to byxp).

However, ifxorxprefers to a dependent type that is not the current instantiation, the type ofyis always dependent.

— _end note_]

A braced-init-list is type-dependent if any element is type-dependent or is a pack expansion.

13.8.3.4 Value-dependent expressions [temp.dep.constexpr]

Except as described below, an expression used in a context where a constant expression is required is value-dependent if any subexpression is value-dependent.

Anid-expressionis value-dependent if

Expressions of the following form are value-dependent:

unless the identifier is a structured binding pack whose initializer is not dependent.

An expression of the form &qualified-id where thequalified-id names a dependent member of the current instantiation is value-dependent.

An expression of the form &cast-expressionis also value-dependent if evaluating cast-expressionas a core constant expression succeeds and the result of the evaluation refers to a templated entity that is an object with static or thread storage duration or a member function.

13.8.3.5 Dependent template arguments [temp.dep.temp]

A constanttemplate-argumentis dependent if its type is dependent or the constant expression it specifies is value-dependent.

Furthermore, a constanttemplate-argumentis dependent if the corresponding constant template parameter is of reference or pointer type and the template-argumentdesignates or points to a member of the current instantiation or a member of a dependent type.

A template argument is also dependent if it is a pack expansion.

A template template parameter is dependent if it names a template parameter or its terminal name is dependent.

13.8.4 Dependent name resolution [temp.dep.res]

13.8.4.1 Point of instantiation [temp.point]

For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization.

Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.

If a function template or member function of a class template is called in a way which uses the definition of a default argument of that function template or member function, the point of instantiation of the default argument is the point of instantiation of the function template or member function specialization.

For a noexcept-specifier of a function template specialization or specialization of a member function of a class template, if the noexcept-specifier is implicitly instantiated because it is needed by another template specialization and the context that requires it depends on a template parameter, the point of instantiation of thenoexcept-specifier is the point of instantiation of the specialization that requires it.

Otherwise, the point of instantiation for such a noexcept-specifier immediately follows the namespace scope declaration or definition that requires thenoexcept-specifier.

For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template.

Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.

If a virtual function is implicitly instantiated, its point of instantiation is immediately following the point of instantiation of its enclosing class template specialization.

An explicit instantiation definition is an instantiation point for the specialization or specializations specified by the explicit instantiation.

A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above,

A specialization for a class template has at most one point of instantiation within a translation unit.

A specialization for any template may have points of instantiation in multiple translation units.

If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.

13.8.4.2 Candidate functions [temp.dep.candidate]

If a dependent call ([temp.dep]) would be ill-formed or would find a better match had the lookup for its dependent name considered all the function declarations with external linkage introduced in the associated namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts ([basic.lookup.argdep]), then the program is ill-formed, no diagnostic required.

[Example 1:

Source file "X.h":namespace Q { struct X { };}

Source file "G.h":namespace Q { void g_impl(X, X);}

Module interface unit of M1:module;#include "X.h" #include "G.h" export module M1;export template<typename T> void g(T t) { g_impl(t, Q::X{ }); }

Module interface unit of M2:module;#include "X.h" export module M2;import M1;void h(Q::X x) { g(x); } — _end example_]

[Example 2:

Module interface unit of Std:export module Std;export template<typename Iter> void indirect_swap(Iter lhs, Iter rhs) { swap(*lhs, *rhs); }

Module interface unit of M:export module M;import Std;struct S { };void swap(S&, S&); void f(S* p, S* q) { indirect_swap(p, q); } — _end example_]

[Example 3:

Source file "X.h":struct X { }; X operator+(X, X);

Module interface unit of F:export module F;export template<typename T> void f(T t) { t + t;}

Module interface unit of M:module;#include "X.h" export module M;import F;void g(X x) { f(x); } — _end example_]

[Example 4:

Module interface unit of A:export module A;export template<typename T> void f(T t) { cat(t, t); dog(t, t); }

Module interface unit of B:export module B;import A;export template<typename T, typename U> void g(T t, U u) { f(t);}

Source file "foo.h", not an importable header:struct foo { friend int cat(foo, foo);};int dog(foo, foo);

Module interface unit of C1:module;#include "foo.h" export module C1;import B;export template<typename T> void h(T t) { g(foo{ }, t);}

Translation unit:import C1;void i() { h(0); }

Importable header "bar.h":struct bar { friend int cat(bar, bar);};int dog(bar, bar);

Module interface unit of C2:module;#include "bar.h" export module C2;import B;export template<typename T> void j(T t) { g(bar{ }, t);}

Translation unit:import C2;void k() { j(0); } — _end example_]