[temp.res] (original) (raw)

13 Templates [temp]

13.8 Name resolution [temp.res]

Three kinds of names can be used within a template definition:

A name used in a template declaration or definition and that is dependent on atemplate-parameteris assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keywordtypename.

[ Example

:

class X;

template class Y { class Z;

void f() { X* a1;
T* a2;
Y* a3;
Z* a4;
typedef typename T::A TA; TA* a5;
typename T::A* a6;
T::A* a7;

B* a8;                      
                            

} };

end example

]

typename-specifier: typename nested-name-specifier identifier typename nested-name-specifier template simple-template-id

A typename-specifierdenotes the type or class template denoted by the simple-type-specifierformed by omitting the keyword typename.

[ Example

:

struct A { struct X { }; int X; }; struct B { struct X { }; }; template void f(T t) { typename T::X x; } void foo() { A a; B b; f(b);
f(a);
}

end example

]

[ Note

:

Thetypenamekeyword is not permitted by the syntax of these constructs.

end note

]

A qualified-idis assumed to name a type if

A qualified name is said to be in a type-id-only contextif it appears in atype-id,new-type-id, ordefining-type-idand the smallest enclosingtype-id,new-type-id, ordefining-type-idis anew-type-id,defining-type-id,trailing-return-type, default argument of a type-parameter of a template, ortype-id of astatic_­cast,const_­cast,reinterpret_­cast, ordynamic_­cast.

[ Example

:

template T::R f();
template void f(T::R);

template struct S { using Ptr = PtrTraits::Ptr;
T::R f(T::P p) {
return static_cast<T::R>(p);
} auto g() -> S<T*>::Ptr;
}; template void f() { void (*pf)(T::X);
void g(T::X);

}

end example

]

A qualified-id that refers to a member of an unknown specialization, that is not prefixed by typename, and that is not otherwise assumed to name a type (see above) denotes a non-type.

[ Example

:

template void f(int i) { T::x * i;
}

struct Foo { typedef int x; };

struct Bar { static int const x = 5; };

int main() { f(1);
f(1);
}

end example

]

Within the definition of a class template or within the definition of a member of a class template following the declarator-id, the keywordtypenameis not required when referring to a member of the current instantiation ([temp.dep.type]).

[ Example

:

template struct A { typedef int B; B b;
};

end example

]

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

[ Note

:

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:

Otherwise, no diagnostic shall be issued for a template for which a valid specialization can be generated.

[ Note

:

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

:

int j; template class X { void f(T t, int i, char* p) { t = i;
p = i;
p = j;
} 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

]

When looking for the declaration of a name used in a template definition, the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) are used for non-dependent names.

The lookup of names dependent on the template parameters is postponed until the actual template argument is known ([temp.dep]).

[ Example

:

#include using namespace std;

template class Set { T* p; int cnt; public: Set(); Set(const Set&); void printall() { for (int i = 0; i<cnt; i++) cout << p[i] << '\n'; } };

In the example,iis the local variableideclared inprintall,cntis the membercntdeclared inSet, andcoutis the standard output stream declared iniostream.

However, not every declaration can be found this way; the resolution of some names must be postponed until the actualtemplate-argumentsare known.

For example, even though the nameoperator<<is known within the definition ofprintall()and a declaration of it can be found in<iostream>, the actual declaration ofoperator<<needed to printp[i]cannot be known until it is known what typeTis ([temp.dep]).

end example

]

If a name does not depend on atemplate-parameter(as defined in [temp.dep]), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation.

[ Example

:

void f(char);

template 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

]

13.8.1 Locally declared names [temp.local]

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

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

[ Example

:

template<template class T> class A { }; template class Y; template<> class Y { Y* p;
Y* q;
A* a;
class B { template 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 in scope.

[ Example

:

template struct Base { Base* p; };

template struct Derived: public Base { typename Derived::Base* p;
};

template<class T, template class U = T::template Base> struct Third { }; Third<Derived > 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

:

template struct Base { }; template struct Derived: Base, Base { typename Derived::Base b;
typename Derived::Base 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

:

template class X { X* p;
X* p2; X* p3; ::X* p4;

};

end example

]

The name of atemplate-parametershall not be redeclared within its scope (including nested scopes).

[ Example

:

template<class T, int i> class Y { int T;
void f() { char T;
} };

template class X;

end example

]

In the definition of a member of a class template that appears outside of the class template definition, the name of a member of the class template hides the name of atemplate-parameterof any enclosing class templates (but not a template-parameter of the member if the member is a class or function template).

[ Example

:

template struct A { struct B { }; typedef void C; void f(); template void g(U); };

template void A::f() { B b;
}

template template void A::g(C) { B b;
C c;
}

end example

]

In the definition of a member of a class template that appears outside of the namespace containing the class template definition, the name of atemplate-parameterhides the name of a member of this namespace.

[ Example

:

namespace N { class C { }; template class B { void f(T); }; } template void N::B::f(C) { C b;
}

end example

]

In the definition of a class template or in the definition of a member of such a template that appears outside of the template definition, for each non-dependent base class ([temp.dep.type]), if the name of the base class or the name of a member of the base class is the same as the name of atemplate-parameter, the base class name or member name hides thetemplate-parametername.

[ Example

:

struct A { struct B { }; int a; int Y; };

template<class B, class a> struct X : A { B b;
a b;
};

end example

]

13.8.2 Dependent names [temp.dep]

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

Such a construct depends on 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 in this subclause.

If an operand of an operator is a type-dependent expression, the operator also denotes a dependent name.

[ Note

:

Such names are unbound and are looked up 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

:

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

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

end example

]

In the definition of a class or class template, the scope of a dependent base classis not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

[ Example

:

typedef double A; template class B { typedef int A; }; template struct X : B { A a;
};

The type nameAin the definition ofX<T>binds to the typedef name defined in the global namespace scope, not to the typedef name defined in the base classB<T>.

end example

]

[ Example

:

struct A { struct B { }; int a; int Y; };

int a;

template struct Y : T { struct B { }; B b;
void f(int i) { a = i; }
Y* p;
};

Y ya;

The membersA​::​B,A​::​a, andA​::​Yof the template argumentAdo not affect the binding of names inY<A>.

end example

]

13.8.2.1 Dependent types [temp.dep.type]

A name refers to thecurrent instantiationif it is

The template argument list of a primary template is a template argument list in which thetemplate argument has the value of thetemplate parameter of the class template.

If the template parameter is atemplate parameter pack, the template argument is apack expansion whose pattern is the name of the template parameter pack.

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.

For a template type-parameter, a template argument is equivalent to a template parameter if it denotes the same type.

For a non-type template parameter, a template argument is equivalent to a 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

:

Using a parenthesized variable name breaks the equivalence.

end note

]

[ Example

:

template class A { A* p1;
A* p2;
A<T*> p3;
::A* p4;
class B { B* p1;
A::B* p2;
typename A<T*>::B* p3;
}; };

template class A<T*> { A<T*>* p1;
A* 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

:

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

[ Example

:

template struct A { typedef int M; struct B { typedef void M; struct C; }; };

template struct A::B::C : A { M m;
};

end example

]

end note

]

A name is amember of the current instantiationif it is

[ Example

:

template class A { static const int i = 5; int n1[i];
int n2[A::i];
int n3[A::i];
int f(); };

template int A::f() { return i;
}

end example

]

A name is 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 of a class that is the current instantiation.

A name is amember of an unknown specializationif it is

If a qualified-id in which the nested-name-specifierrefers 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 A { typedef int type; void f() { A::type i;
typename A::other j;

} };

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 aqualified-id or class member access expression, the name in thequalified-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.

[ Example

:

struct A { int m; };

struct B { int m; };

template struct C : A, T { int f() { return this->m; }
int g() { return m; }
};

template int C::f();
template int C::g();

end example

]

A type is dependent if it is

[ 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

]

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

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

thisis type-dependent if the class type of the enclosing member function is dependent ([temp.dep.type]).

Anid-expressionis type-dependent if it is not a concept-id and it contains

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 type-dependent only if the type specified by thetype-id,simple-type-specifierornew-type-idis dependent, even if any subexpression is type-dependent:

simple-type-specifier ( expression-list ) :: new new-placement new-type-id new-initializer :: new new-placement ( type-id ) new-initializer dynamic_­cast < type-id > ( expression ) static_­cast < type-id > ( expression ) const_­cast < type-id > ( expression ) reinterpret_­cast < type-id > ( expression ) ( type-id ) cast-expression

A class member access expression is type-dependent if the expression refers to a member of the current instantiation and the type of the referenced member is dependent, or the class member access expression refers to a member of an unknown specialization.

[ Note

:

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.

Ifxor xprefers to a non-dependent type or refers to the current instantiation, the type ofyis the type of the class member access expression.

end note

]

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

13.8.2.3 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 if theunary-expression or expressionis type-dependent or thetype-idis dependent:

sizeof unary-expression sizeof ( type-id ) typeid ( expression ) typeid ( type-id ) alignof ( type-id ) noexcept ( expression )

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.2.4 Dependent template arguments [temp.dep.temp]

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

13.8.3 Non-dependent names [temp.nondep]

Non-dependent names used in a template definition are found using the usual name lookup and bound at the point they are used.

[ Example

:

void g(double); void h();

template class Z { public: void f() { g(1);
h++;

} };

void g(int);

end example

]

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]

[ Note

:

For the part of the lookup using associated namespaces ([basic.lookup.argdep]), function declarations found in the template instantiation context are found by this lookup, as described in [basic.lookup.argdep].

end note

]

If the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.

[ Example

:

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

:

Module interface unit of Std:

export module Std; export template 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

:

Source file "X.h":

struct X { }; X operator+(X, X);

Module interface unit of F:

export module F; export template 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

:

Module interface unit of A:

export module A; export template 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 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 void j(T t) { g(bar{ }, t); }

Translation unit:

import C2; void k() { j(0);

}

end example

]

13.8.5 Friend names declared within a class template [temp.inject]

Friend classes or functions can be declared within a class template.

When a template is instantiated, the names of its friends are treated as if the specialization had been explicitly declared at its point of instantiation.

As with non-template classes, the names of namespace-scope friend functions of a class template specialization are not visible during an ordinary lookup unless explicitly declared at namespace scope ([class.friend]).

Such names may be found under the rules for associated classes ([basic.lookup.argdep]).137

[ Example

:

template struct number { number(int); friend number gcd(number x, number y) { return 0; }; };

void g() { number a(3), b(4); a = gcd(a,b);

b = gcd(3,4);
}

end example

]