Files
2025-10-25 03:02:53 +03:00

27 KiB
Raw Permalink Blame History

[temp.arg]

13 Templates [temp]

13.4 Template arguments [temp.arg]

13.4.1 General [temp.arg.general]

1

#

The type and form of each template-argument specified in a template-id or in a splice-specialization-specifier shall match the type and form specified for the corresponding parameter declared by the template in itstemplate-parameter-list.

When the parameter declared by the template is atemplate parameter pack, it will correspond to zero or moretemplate-arguments.

[Example 1: template class Array { T* v; int sz;public:explicit Array(int); T& operator; T& elem(int i) { return v[i]; }};

Array v1(20);typedef std::complex dcomplex; // std::complex is a standard library template Array v2(30); Array v3(40);

void bar() { v1[3] = 7; v2[3] = v3.elem(4) = dcomplex(7,8);} — end example]

2

#

The template argument list of a template-head is a template argument list in which the nth template argument has the value of the nth template parameter of the template-head.

If the nth template parameter is a template parameter pack ([temp.variadic]), the nth template argument is a pack expansion whose pattern is the name of the template parameter pack.

3

#

In atemplate-argument, an ambiguity between atype-id and an expression is resolved to atype-id, regardless of the form of the correspondingtemplate-parameter.109

[Example 2: template void f();template void f();

void g() { f<int()>(); // int() is a type-id: call the first f()} — end example]

4

#

[Note 1:

Names used in a template-argument are subject to access control where they appear.

Because a template parameter is not a class member, no access control applies where the template parameter is used.

— end note]

[Example 3: template class X {static T t;};

class Y {private:struct S { /* ... */ }; X x; // OK, S is accessible// X<Y::S> has a static member of type Y::S// OK, even though Y::S is private};

X<Y::S> y; // error: S not accessible — end example]

For a template argument that is a class type or a class template, the template definition has no special access rights to the members of the template argument.

[Example 4: template <template class T> class A {typename T::S s;};

template class B {private:struct S { /* ... */ };};

A b; // error: A has no access to B::S — end example]

5

#

When template argument packs or default template arguments are used, a template-argument list can be empty.

In that case the empty<> brackets shall still be used as thetemplate-argument-list.

[Example 5: template class String; String<>* p; // OK, String String* q; // syntax errortemplate<class ... Elements> class Tuple; Tuple<>* t; // OK, Elements is empty Tuple* u; // syntax error — end example]

6

#

An explicit destructor call ([class.dtor]) for an object that has a type that is a class template specialization may explicitly specify thetemplate-arguments.

[Example 6: template struct A {~A();};void f(A* p, A* q) { p->A::~A(); // OK, destructor call q->A::~A(); // OK, destructor call} — end example]

7

#

If the use of a template argument gives rise to an ill-formed construct in the instantiation of a template specialization, the program is ill-formed.

8

#

When name lookup for the component name of atemplate-id finds an overload set, both non-template functions in the overload set and function templates in the overload set for which thetemplate-arguments do not match thetemplate-parameters are ignored.

[Note 2:

If none of the function templates have matchingtemplate-parameters, the program is ill-formed.

— end note]

9

#

When a simple-template-id orsplice-specialization-specifier does not designate a function, a default template-argument isimplicitly instantiated when the value of that default argument is needed.

[Example 7: template<typename T, typename U = int> struct S { }; S* p; // the type of p is S<bool, int>*

The default argument for U is instantiated to form the type S<bool, int>*.

— end example]

10

#

A template-argument followed by an ellipsis is a pack expansion.

109)109)

There is no such ambiguity in a defaulttemplate-argument because the form of thetemplate-parameter determines the allowable forms of thetemplate-argument.

13.4.2 Type template arguments [temp.arg.type]

1

#

Atemplate-argument for a type template parameter shall be atype-id.

2

#

[Example 1: template class X { };template void f(T t) { }struct { } unnamed_obj;

void f() {struct A { }; enum { e1 }; typedef struct { } B; B b; X x1; // OK X<A*> x2; // OK X x3; // OK f(e1); // OK f(unnamed_obj); // OK f(b); // OK} — end example]

[Note 1:

A template type argument can be an incomplete type ([basic.types.general]).

— end note]

13.4.3 Constant template arguments [temp.arg.nontype]

1

#

A template argument E for a constant template parameter with declared type T shall be such that the invented declarationT x = E ; satisfies the semantic constraints for the definition of a constexpr variable with static storage duration ([dcl.constexpr]).

If T contains a placeholder type ([dcl.spec.auto]) or a placeholder for a deduced class type ([dcl.type.class.deduct]), the type of the parameter is deduced from the above declaration.

[Note 1:

E is a template-argument or (for a default template argument) an initializer-clause.

— end note]

If the parameter type thus deduced is not permitted for a constant template parameter ([temp.param]), the program is ill-formed.

2

#

The value of a constant template parameter P of (possibly deduced) type T is determined from its template argument A as follows.

If T is not a class type andA is not a braced-init-list,A shall be a converted constant expression ([expr.const]) of type T; the value of P is A (as converted).

3

#

Otherwise, a temporary variableconstexpr T v = A; is introduced.

The lifetime of v ends immediately after initializing it and any template parameter object (see below).

For each such variable, the id-expression v is termed a candidate initializer.

4

#

If T is a class type, a template parameter object ([temp.param]) exists that is constructed so as to be template-argument-equivalent to v;P denotes that template parameter object.

P is copy-initialized from an unspecified candidate initializer that is template-argument-equivalent to v.

If, for the initialization from any candidate initializer,

the initialization would be ill-formed, or

the full-expression of an invented init-declarator for the initialization would not be a constant expression when interpreted as a constant-expression ([expr.const]), or

the initialization would cause P to not be template-argument-equivalent ([temp.type]) to v,

the program is ill-formed.

5

#

Otherwise, the value of P is that of v.

6

#

For a constant template parameter of reference or pointer type, or for each non-static data member of reference or pointer type in a constant template parameter of class type or subobject thereof, the reference or pointer value shall not refer or point to (respectively):

a temporary object ([class.temporary]),

a string literal object ([lex.string]),

the result of a typeid expression ([expr.typeid]),

a predefined func variable ([dcl.fct.def.general]), or

a subobject ([intro.object]) of one of the above.

7

#

[Example 1: template <int& r> class A{};extern int x; A a; // OKvoid f(int p) {constexpr int& r = p; // OK A a; // error: a static constexpr int& variable cannot be initialized to refer to p here} — end example]

8

#

[Example 2: template<const int* pci> struct X { /* ... / };int ai[10]; X xi; // array to pointer and qualification conversionsstruct Y { / ... / };template<const Y& b> struct Z { / ... / }; Y y; Z z; // no conversion, but note extra cv-qualificationtemplate<int (&pa)[5]> struct W { / ... */ };int b[5]; W w; // no conversionvoid f(char);void f(int);

template<void (pf)(int)> struct A { / ... */ };

A<&f> a; // selects f(int)template struct B { /* ... / }; B<5> b1; // OK, template parameter type is int B<'a'> b2; // OK, template parameter type is char B<2.5> b3; // OK, template parameter type is double B<void(0)> b4; // error: template parameter type cannot be voidtemplate struct C { / ... */ }; C<{ 42 }> c1; // OKstruct J1 { J1 *self = this;}; B<J1{}> j1; // error: initialization of template parameter object is not a constant expressionstruct J2 { J2 *self = this; constexpr J2() {}constexpr J2(const J2&) {}}; B<J2{}> j2; // error: template parameter object not template-argument-equivalent to introduced temporary — end example]

9

#

[Note 2:

A string-literal ([lex.string]) is not an acceptable template-argument for a constant template parameter of non-class type.

[Example 3: template<class T, T p> class X {/* ... */};

X<const char*, "Studebaker"> x; // error: string literal object as template-argument X<const char*, "Knope" + 1> x2; // error: subobject of string literal object as template-argumentconst char p[] = "Vivisectionist"; X<const char*, p> y; // OKstruct A {constexpr A(const char*) {}};

X<A, "Pyrophoricity"> z; // OK, string-literal is a constructor argument to A — end example]

— end note]

10

#

[Note 3:

A temporary object is not an acceptabletemplate-argument when the corresponding template parameter has reference type.

[Example 4: template<const int& CRI> struct B { /* ... */ };

B<1> b1; // error: temporary would be required for template argumentint c = 1; B b2; // OKstruct X { int n; };struct Y { const int &r; };template struct C { /* ... */ }; C<Y{X{1}.n}> c; // error: subobject of temporary object used to initialize// reference member of template parameter — end example]

— end note]

13.4.4 Template template arguments [temp.arg.template]

1

#

Atemplate-argument for a template template parameter shall be the name of a template.

For a type-tt-parameter, the name shall denote a class template or alias template.

For a variable-tt-parameter, the name shall denote a variable template.

For a concept-tt-parameter, the name shall denote a concept.

Only primary templates are considered when matching the template template argument with the corresponding parameter; partial specializations are not considered even if their parameter lists match that of the template template parameter.

2

#

Any partial specializations ([temp.spec.partial]) associated with the primary template are considered when a specialization based on the template template parameter is instantiated.

If a specialization is not reachable from the point of instantiation, and it would have been selected had it been reachable, the program is ill-formed, no diagnostic required.

[Example 1: template class A { // primary templateint x;};template class A<T*> { // partial specializationlong x;};template<template class V> class C { V y; V<int*> z;}; C c; // V within C uses the primary template, so c.y.x has type int// V<int*> within C uses the partial specialization, so c.z.x has type long — end example]

3

#

A template template parameter P and a template-argument A arecompatible if

A denotes a class template or an alias template andP is a type template parameter,

A denotes a variable template andP is a variable template parameter, or

A denotes a concept andP is a concept template parameter.

4

#

A template template-argument A matches a template template parameter P whenA and P are compatible andP is at least as specialized as A, ignoring constraints on A if P is unconstrained.

If P contains a template parameter pack, then A also matches P if each of A's template parameters matches the corresponding template parameter declared in thetemplate-head of P.

Two template parameters match if they are of the same kind, for constant template parameters, their types are equivalent ([temp.over.link]), and for template template parameters, each of their corresponding template parameters matches, recursively.

When P's template-head contains a template-parameter that declares a template parameter pack ([temp.variadic]), the template parameter pack will match zero or more template parameters or template parameter packs declared in the template-head ofA with the same type and form as the template parameter pack declared in P (ignoring whether those template parameters are template parameter packs).

[Example 2: template class A { /* ... / };template<class T, class U = T> class B { / ... / };template<class ... Types> class C { / ... / };template class D { / ... / };template<template class P> class X { / ... / };template<template<class ...> class Q> class Y { / ... / };template<template class R> class Z { / ... */ };

X xa; // OK X xb; // OK X xc; // OK Y ya; // OK Y yb; // OK Y yc; // OK Z zd; // OK — end example]

[Example 3: template struct eval;

template <template <class, class...> class TT, class T1, class... Rest>struct eval<TT<T1, Rest...>> { };

template struct A;template <class T1, class T2> struct B;template struct C;template <class T1, int N> struct D;template <class T1, class T2, int N = 17> struct E;

eval<A> eA; // OK, matches partial specialization of eval eval<B<int, float>> eB; // OK, matches partial specialization of eval eval<C<17>> eC; // error: C does not match TT in partial specialization eval<D<int, 17>> eD; // error: D does not match TT in partial specialization eval<E<int, float>> eE; // error: E does not match TT in partial specialization — end example]

[Example 4: template concept C = requires (T t) { t.f(); };template concept D = C && requires (T t) { t.g(); };

template<template class P> struct S { };

template struct X { };template struct Y { };template struct Z { };

S s1; // OK, X and P have equivalent constraints S s2; // error: P is not at least as specialized as Y S s3; // OK, P is at least as specialized as Z — end example]

5

#

A template template parameter P is at least as specialized as a template template-argument A if, given the following rewrite to two function templates, the function template corresponding to P is at least as specialized as the function template corresponding to A according to the partial ordering rules for function templates.

Given an invented class template X with the template-head of A (including default arguments and requires-clause, if any):

  • (5.1)

    Each of the two function templates has the same template parameters and requires-clause (if any), respectively, as P or A.

  • (5.2)

    Each function template has a single function parameter whose type is a specialization of X with template arguments corresponding to the template parameters from the respective function template where, for each template-parameter PP in the template-head of the function template, a corresponding template-argument AA is formed. If PP declares a template parameter pack, then AA is the pack expansion PP... ([temp.variadic]); otherwise, AA is an id-expression denoting PP.

If the rewrite produces an invalid type, then P is not at least as specialized as A.