template-declaration: template-head declaration template-head concept-definition
template-head: template < template-parameter-list > requires-clause
template-parameter-list: template-parameter template-parameter-list , template-parameter
requires-clause: requires constraint-logical-or-expression
constraint-logical-or-expression: constraint-logical-and-expression constraint-logical-or-expression || constraint-logical-and-expression
constraint-logical-and-expression: primary-expression constraint-logical-and-expression && primary-expression
concept-definition: concept concept-name = constraint-expression ;
concept-name: identifier
template<class T>
constexpr T pi = T(3.1415926535897932385L);
template<class T>
T circular_area(T r) {
return pi<T> * r * r;
}
struct matrix_constants {
template<class T>
using pauli = hermitian_matrix<T, 2>;
template<class T>
constexpr pauli<T> sigma1 = { { 0, 1 }, { 1, 0 } };
template<class T>
constexpr pauli<T> sigma2 = { { 0, -1i }, { 1i, 0 } };
template<class T>
constexpr pauli<T> sigma3 = { { 1, 0 }, { 0, -1 } };
}; — end example
template<int N> requires N == sizeof new unsigned short
int f(); // error: parentheses required around == expression
— end exampletemplate-parameter: type-parameter parameter-declaration constrained-parameter
type-parameter: type-parameter-key ... identifier type-parameter-key identifier = type-id template-head type-parameter-key ... identifier template-head type-parameter-key identifier = id-expression
type-parameter-key: class typename
constrained-parameter: qualified-concept-name ... identifier qualified-concept-name identifier default-template-argument
qualified-concept-name: nested-name-specifier concept-name nested-name-specifier partial-concept-id
partial-concept-id: concept-name < template-argument-list >
default-template-argument: = type-id = id-expression = initializer-clause
class T { /* ... */ };
int i;
template<class T, T i> void f(T t) {
T t1 = i; // template-parameters T and i
::T t2 = ::i; // global namespace members T and i
}
struct A { auto operator<=>(A, A) = default; };
template<const X& x, int i, A a> void f() {
i++; // error: change of template-parameter value
&x; // OK
&i; // error: address of non-reference template-parameter
&a; // OK
int& ri = i; // error: non-const reference bound to temporary
const int& cri = i; // OK: const reference bound to temporary
const A& ra = a; // OK: const reference bound to a template parameter object
} — end exampletemplate<double d> class X; // error template<double* pd> class Y; // OK template<double& rd> class Z; // OK— end example
template<int* a> struct R { /* ... */ };
template<int b[5]> struct S { /* ... */ };
int p;
R<&p> w; // OK
S<&p> x; // OK due to parameter adjustment
int v[5];
R<v> y; // OK due to implicit argument conversion
S<v> z; // OK due to both adjustment and conversion
— end exampletemplate<typename T> concept C1 = true; template<template<typename> class X> concept C2 = true; template<int N> concept C3 = true; template<typename... Ts> concept C4 = true; template<char... Cs> concept C5 = true; template<C1 T> void f1(); // OK, T is a type template-parameter template<C2 X> void f2(); // OK, X is a template with one type-parameter template<C3 N> void f3(); // OK, N has type int template<C4... Ts> void f4(); // OK, Ts is a template parameter pack of types template<C4 T> void f5(); // OK, T is a type template-parameter template<C5... Cs> void f6(); // OK, Cs is a template parameter pack of chars— end example
template<typename T> concept C1 = true; template<typename... Ts> concept C2 = true; template<typename T, typename U> concept C3 = true; template<C1 T> struct s1; // associates C1<T> template<C1... T> struct s2; // associates (C1<T> && ...) template<C2... T> struct s3; // associates C2<T...> template<C3<int> T> struct s4; // associates C3<T, int>— end example
template<typename T> concept C1 = true; template<int N> concept C2 = true; template<template<typename> class X> concept C3 = true; template<typename T> struct S0; template<C1 T = int> struct S1; // OK template<C2 N = 0> struct S2; // OK template<C3 X = S0> struct S3; // OK template<C1 T = 0> struct S4; // error: default argument is not a type— end example
template<class T1, class T2 = int> class A; template<class T1 = int, class T2> class A;
template<class T1 = int, class T2 = int> class A;— end example
template<class T1 = int, class T2> class B; // error // U can be neither deduced from the parameter-type-list nor specified template<class... T, class... U> void f() { } // error template<class... T, class U> void g() { } // error— end example
template<class T = int> class X;
template<class T = int> class X { /* ... */ }; // error
— end exampletemplate<int i = 3 > 4 > // syntax error class X { /* ... */ }; template<int i = (3 > 4) > // OK class Y { /* ... */ };— end example
template <class T = float> struct B {};
template <template <class TT = float> class T> struct A {
inline void f();
inline void g();
};
template <template <class TT> class T> void A<T>::f() {
T<> t; // error: TT has no default template argument
}
template <template <class TT = char> class T> void A<T>::g() {
T<> t; // OK, T<char>
} — end exampletemplate <class... Types> // Types is a template type parameter pack class Tuple; // but not a pack expansion template <class T, int... Dims> // Dims is a non-type template parameter pack struct multi_array; // but not a pack expansion template <class... T> struct value_holder { template <T... Values> struct apply { }; // Values is a non-type template parameter pack }; // and a pack expansion template <class... T, T... Values> // error: Values expands template type parameter struct static_array; // pack T within the same template parameter list— end example
simple-template-id: template-name < template-argument-list >
template-id: simple-template-id operator-function-id < template-argument-list > literal-operator-id < template-argument-list >
template-name: identifier
template-argument-list: template-argument ... template-argument-list , template-argument ...
template-argument: constant-expression type-id id-expression
template<int i> class X { /* ... */ };
X< 1>2 > x1; // syntax error
X<(1>2)> x2; // OK
template<class T> class Y { /* ... */ };
Y<X<1>> x3; // OK, same as Y<X<1> > x3;
Y<X<6>>1>> x4; // syntax error
Y<X<(6>>1)>> x5; // OK
— end example
struct X {
template<std::size_t> X* alloc();
template<std::size_t> static X* adjust();
};
template<class T> void f(T* p) {
T* p1 = p->alloc<200>(); // ill-formed: < means less than
T* p2 = p->template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
} — end example
template <class T> struct A {
void f(int);
template <class U> void f(U);
};
template <class T> void f(T t) {
A<T> a;
a.template f<>(t); // OK: calls template
a.template f(t); // error: not a template-id
}
template <class T> struct B {
template <class T2> struct C { };
};
// OK: T::template C names a class template:
template <class T, template <class X> class TT = T::template C> struct D { };
D<B<int> > db; — end example
template<class T, T::type n = 0> class X;
struct S {
using type = int;
};
using T1 = X<S, int, int>; // error: too many arguments
using T2 = X<>; // error: no default argument for first template parameter
using T3 = X<1>; // error: value 1 does not match type-parameter
using T4 = X<int>; // error: substitution failure for second template parameter
using T5 = X<S>; // OK
— end example
template<typename T> concept C1 = sizeof(T) != sizeof(int);
template<C1 T> struct S1 { };
template<C1 T> using Ptr = T*;
S1<int>* p; // error: constraints not satisfied
Ptr<int> p; // error: constraints not satisfied
template<typename T>
struct S2 { Ptr<int> x; }; // error, no diagnostic required
template<typename T>
struct S3 { Ptr<T> x; }; // OK, satisfaction is not required
S3<int> x; // error: constraints not satisfied
template<template<C1 T> class X>
struct S4 {
X<int> x; // error, no diagnostic required
};
template<typename T> concept C2 = sizeof(T) == 1;
template<C2 T> struct S { };
template struct S<char[2]>; // error: constraints not satisfied
template<> struct S<char[2]> { }; // error: constraints not satisfied
— end example
template<class T> class Array {
T* v;
int sz;
public:
explicit Array(int);
T& operator[](int);
T& elem(int i) { return v[i]; }
};
Array<int> v1(20);
typedef std::complex<double> dcomplex; // std::complex is a standard library template
Array<dcomplex> v2(30);
Array<dcomplex> v3(40);
void bar() {
v1[3] = 7;
v2[3] = v3.elem(4) = dcomplex(7,8);
} — end example
template<class T> void f();
template<int I> void f();
void g() {
f<int()>(); // int() is a type-id: call the first f()
} — end example
template<class T> class X {
static T t;
};
class Y {
private:
struct S { /* ... */ };
X<S> 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
template <template <class TT> class T> class A {
typename T<int>::S s;
};
template <class U> class B {
private:
struct S { /* ... */ };
};
A<B> b; // ill-formed: A has no access to B::S
— end exampletemplate<class T = char> class String; String<>* p; // OK: String<char> String* q; // syntax error template<class ... Elements> class Tuple; Tuple<>* t; // OK: Elements is empty Tuple* u; // syntax error— end example
template<class T> struct A {
~A();
};
void f(A<int>* p, A<int>* q) {
p->A<int>::~A(); // OK: destructor call
q->A<int>::~A<int>(); // OK: destructor call
} — end example
template <class T> class X { };
template <class T> void f(T t) { }
struct { } unnamed_obj;
void f() {
struct A { };
enum { e1 };
typedef struct { } B;
B b;
X<A> x1; // OK
X<A*> x2; // OK
X<B> x3; // OK
f(e1); // OK
f(unnamed_obj); // OK
f(b); // OK
} — end exampleT x = template-argument ;If a deduced parameter type is not permitted for a template-parameter declaration ([temp.param]), the program is ill-formed.
template<const int* pci> struct X { /* ... */ };
int ai[10];
X<ai> xi; // array to pointer and qualification conversions
struct Y { /* ... */ };
template<const Y& b> struct Z { /* ... */ };
Y y;
Z<y> z; // no conversion, but note extra cv-qualification
template<int (&pa)[5]> struct W { /* ... */ };
int b[5];
W<b> w; // no conversion
void f(char);
void f(int);
template<void (*pf)(int)> struct A { /* ... */ };
A<&f> a; // selects f(int)
template<auto n> struct B { /* ... */ };
B<5> b1; // OK: template parameter type is int
B<'a'> b2; // OK: template parameter type is char
B<2.5> b3; // error: template parameter type cannot be double
— end example
template<class T, T p> class X {
/* ... */
};
X<const char*, "Studebaker"> x; // error: string literal as template-argument
const char p[] = "Vivisectionist";
X<const char*, p> y; // OK
class A {
constexpr A(const char*) {}
auto operator<=>(A, A) = default;
};
X<A, "Pyrophoricity"> z; // OK, string literal is a constructor argument to A
— end example
template<int* p> class X { };
int a[10];
struct S { int m; static int s; } s;
X<&a[2]> x3; // error: address of array element
X<&s.m> x4; // error: address of non-static member
X<&s.s> x5; // OK: address of static member
X<&S::s> x6; // OK: address of static member
— end example
template<const int& CRI> struct B { /* ... */ };
B<1> b2; // error: temporary would be required for template argument
int c = 1;
B<c> b1; // OK
— end example
template<class T> class A { // primary template
int x;
};
template<class T> class A<T*> { // partial specialization
long x;
};
template<template<class U> class V> class C {
V<int> y;
V<int*> z;
};
C<A> c; // V<int> within C<A> uses the primary template, so c.y.x has type int
// V<int*> within C<A> uses the partial specialization, so c.z.x has type long
— end example
template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template<class ... Types> class C { /* ... */ };
template<auto n> class D { /* ... */ };
template<template<class> class P> class X { /* ... */ };
template<template<class ...> class Q> class Y { /* ... */ };
template<template<int> class R> class Z { /* ... */ };
X<A> xa; // OK
X<B> xb; // OK
X<C> xc; // OK
Y<A> ya; // OK
Y<B> yb; // OK
Y<C> yc; // OK
Z<D> zd; // OK
— end example
template <class T> struct eval;
template <template <class, class...> class TT, class T1, class... Rest>
struct eval<TT<T1, Rest...>> { };
template <class T1> struct A;
template <class T1, class T2> struct B;
template <int N> struct C;
template <class T1, int N> struct D;
template <class T1, class T2, int N = 17> struct E;
eval<A<int>> 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
template<typename T> concept C = requires (T t) { t.f(); };
template<typename T> concept D = C<T> && requires (T t) { t.g(); };
template<template<C> class P> struct S { };
template<C> struct X { };
template<D> struct Y { };
template<typename T> struct Z { };
S<X> s1; // OK, X and P have equivalent constraints
S<Y> s2; // error: P is not at least as specialized as Y
S<Z> s3; // OK, P is at least as specialized as Z
— end example
template<typename T>
constexpr bool get_value() { return T::value; }
template<typename T>
requires (sizeof(T) > 1) && get_value<T>()
void f(T); // has associated constraint sizeof(T) > 1 ∧ get_value<T>()
void f(int);
f('a'); // OK: calls f(int)
template<typename T> concept C = sizeof(T) == 4 && !true; // requires atomic constraints sizeof(T) == 4 and !true template<typename T> struct S { constexpr operator bool() const { return true; } }; template<typename T> requires (S<T>{}) void f(T); // #1 void f(int); // #2 void g() { f(0); // error: expression S<int>{} does not have type bool } // while checking satisfaction of deduced arguments of #1; // call is ill-formed even though #2 is a better match— end example
constraint-expression: logical-or-expression
template<typename T> concept C = true; template<C T> void f1(T); template<typename T> requires C<T> void f2(T); template<typename T> void f3(T) requires C<T>;
template<typename T> concept C1 = true; template<typename T> concept C2 = sizeof(T) > 0; template<C1 T> void f4(T) requires C2<T>; template<typename T> requires C1<T> && C2<T> void f5(T);
template<C1 T> requires C2<T> void f6(); template<C2 T> requires C1<T> void f7();— end example
template<typename T> concept A = T::value || true; template<typename U> concept B = A<U*>; template<typename V> concept C = B<V&>;
template<typename T> concept C1 = sizeof(T) == 1;
template<typename T> concept C2 = C1<T>() && 1 == 2;
template<typename T> concept C3 = requires { typename T::type; };
template<typename T> concept C4 = requires (T x) { ++x; }
template<C2 U> void f1(U); // #1
template<C3 U> void f2(U); // #2
template<C4 U> void f3(U); // #3
— end example
template<typename T> concept C1 = requires(T t) { --t; };
template<typename T> concept C2 = C1<T> && requires(T t) { *t; };
template<C1 T> void f(T); // #1
template<C2 T> void f(T); // #2
template<typename T> void g(T); // #3
template<C1 T> void g(T); // #4
f(0); // selects #1
f((int*)0); // selects #2
g(true); // selects #3 because C1<bool> is not satisfied
g(0); // selects #4
— end example
template<class E, int size> class buffer { /* ... */ };
buffer<char,2*512> x;
buffer<char,1024> y;
template<class T, void(*err_fct)()> class list { /* ... */ };
list<int,&error_handler1> x1;
list<int,&error_handler2> x2;
list<int,&error_handler2> x3;
list<char,&error_handler2> x4;
template<class T> struct X { };
template<class> struct Y { };
template<class T> using Z = Y<T>;
X<Y<int> > y;
X<Z<int> > z; — end example
template<class T1, class T2, int I> class A<T1, T2, I> { }; // error
template<class T1, int I> void sort<T1, I>(T1 data[I]); // error
— end example
template<class T> class Array {
T* v;
int sz;
public:
explicit Array(int);
T& operator[](int);
T& elem(int i) { return v[i]; }
};
The prefix template<class T>
specifies that a template is being declared and that a
type-name
T
may be used in the declaration.
template<class T1, class T2> struct A {
void f1();
void f2();
};
template<class T2, class T1> void A<T2,T1>::f1() { } // OK
template<class T2, class T1> void A<T1,T2>::f2() { } // error
template<class ... Types> struct B {
void f3();
void f4();
};
template<class ... Types> void B<Types ...>::f3() { } // OK
template<class ... Types> void B<Types>::f4() { } // error
template<typename T> concept C = true;
template<typename T> concept D = true;
template<C T> struct S {
void f();
void g();
void h();
template<D U> struct Inner;
};
template<C A> void S<A>::f() { } // OK: template-heads match
template<typename T> void S<T>::g() { } // error: no matching declaration for S<T>
template<typename T> requires C<T> // error (no diagnostic required): template-heads are
void S<T>::h() { } // functionally equivalent but not equivalent
template<C X> template<D Y>
struct S<X>::Inner { }; // OK
— end example
template<class T> class Array {
T* v;
int sz;
public:
explicit Array(int);
T& operator[](int);
T& elem(int i) { return v[i]; }
};
template<class T> T& Array<T>::operator[](int i) {
if (i<0 || sz<=i) error("Array: range error");
return v[i];
}
template<typename T> concept C = requires {
typename T::type;
};
template<typename T> struct S {
void f() requires C<T>;
void g() requires C<T>;
};
template<typename T>
void S<T>::f() requires C<T> { } // OK
template<typename T>
void S<T>::g() { } // error: no matching function in S<T>
Array<int> v1(20); Array<dcomplex> v2(30); v1[3] = 7; // Array<int>::operator[]() v2[3] = dcomplex(7,8); // Array<dcomplex>::operator[]()— end example
template<class T> struct A {
class B;
};
A<int>::B* b1; // OK: requires A to be defined but not A::B
template<class T> class A<T>::B { };
A<int>::B b2; // OK: requires A::B to be defined
— end note
template<class T> class X {
static T s;
};
template<class T> T X<T>::s = 0;
struct limits {
template<class T>
static const T min; // declaration
};
template<class T>
const T limits::min = { }; // definition
— end example
template <class T> struct A {
static int i[];
};
template <class T> int A<T>::i[4]; // 4 elements
template <> int A<int>::i[] = { 1 }; // OK: 1 element
— end example
template<class T> struct string {
template<class T2> int compare(const T2&);
template<class T2> string(const string<T2>& s) { /* ... */ }
};
template<class T> template<class T2> int string<T>::compare(const T2& s) {
} — end example
template<typename T> concept C1 = true;
template<typename T> concept C2 = sizeof(T) <= 4;
template<C1 T> struct S {
template<C2 U> void f(U);
template<C2 U> void g(U);
};
template<C1 T> template<C2 U>
void S<T>::f(U) { } // OK
template<C1 T> template<typename U>
void S<T>::g(U) { } // error: no matching function in S<T>
— end example
template <class T> struct A {
void f(int);
template <class T2> void f(T2);
};
template <> void A<int>::f(int) { } // non-template member function
template <> template <> void A<int>::f<>(int) { } // member function template specialization
int main() {
A<char> ac;
ac.f(1); // non-template
ac.f('c'); // template
ac.f<>(1); // template
} — end example
template <class T> struct AA {
template <class C> virtual void g(C); // error
virtual void f(); // OK
}; — end example
class B {
virtual void f(int);
};
class D : public B {
template <class T> void f(T); // does not override B::f(int)
void f(int i) { f<>(i); } // overriding function that calls the template instantiation
}; — end example
struct A {
template <class T> operator T*();
};
template <class T> A::operator T*(){ return 0; }
template <> A::operator char*(){ return 0; } // specialization
template A::operator void*(); // explicit instantiation
int main() {
A a;
int* ip;
ip = a.operator int*(); // explicit call to template operator A::operator int*()
} — end example
template<class ... Types> struct Tuple { };
Tuple<> t0; // Types contains no arguments
Tuple<int> t1; // Types contains one argument: int
Tuple<int, float> t2; // Types contains two arguments: int and float
Tuple<0> error; // error: 0 is not a type
— end exampletemplate<class ... Types> void f(Types ... args); f(); // args contains no arguments f(1); // args contains one argument: int f(2, 1.0); // args contains two arguments: int and double— end example
template <typename... Args>
void foo(Args... args) {
[...xs=args]{
bar(xs...); // xs is an init-capture pack
};
}
foo(); // xs contains zero init-captures
foo(1); // xs contains one init-capture
— end example
template<class ... Types> void f(Types ... rest);
template<class ... Types> void g(Types ... rest) {
f(&rest ...); // “&rest ...” is a pack expansion; “&rest” is its pattern
} — end example
template<typename...> struct Tuple {};
template<typename T1, typename T2> struct Pair {};
template<class ... Args1> struct zip {
template<class ... Args2> struct with {
typedef Tuple<Pair<Args1, Args2> ... > type;
};
};
typedef zip<short, int>::with<unsigned short, unsigned>::type T1;
// T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned>>
typedef zip<short>::with<unsigned short, unsigned>::type T2;
// error: different number of arguments specified for Args1 and Args2
template<class ... Args>
void g(Args ... args) { // OK: Args is expanded by the function parameter pack args
f(const_cast<const Args*>(&args)...); // OK: “Args” and “args” are expanded
f(5 ...); // error: pattern does not contain any packs
f(args); // error: pack “args” is not expanded
f(h(args ...) + args ...); // OK: first “args” expanded within h,
// second “args” expanded within f
} — end example
template<class... T> struct X : T... { };
template<class... T> void f(T... values) {
X<T...> x(values...);
}
template void f<>(); // OK: X<> has no base classes
// x is a variable of type X<> that is value-initialized
— end example
template<typename ...Args>
bool all(Args ...args) { return (... && args); }
bool b = all(true, true, true, false);
template<class T> class task;
template<class T> task<T>* preempt(task<T>*);
template<class T> class task {
friend void next_time();
friend void process(task<T>*);
friend task<T>* preempt<T>(task<T>*);
template<class C> friend int func(C);
friend class task<int>;
template<class P> friend class frd;
};
class A {
template<class T> friend class B; // OK
template<class T> friend void f(T){ /* ... */ } // OK
}; — end example
class X {
template<class T> friend struct A;
class Y { };
};
template<class T> struct A { X::Y ab; }; // OK
template<class T> struct A<T*> { X::Y ab; }; // OK
— end example
template<class T> struct A {
struct B { };
void f();
struct D {
void g();
};
T h();
template<T U> T i();
};
template<> struct A<int> {
struct B { };
int f();
struct D {
void g();
};
template<int U> int i();
};
template<> struct A<float*> {
int *h();
};
class C {
template<class T> friend struct A<T>::B; // grants friendship to A<int>::B even though
// it is not a specialization of A<T>::B
template<class T> friend void A<T>::f(); // does not grant friendship to A<int>::f()
// because its return type does not match
template<class T> friend void A<T>::D::g(); // ill-formed: A<T>::D does not end with
// a simple-template-id
template<class T> friend int *A<T*>::h(); // grants friendship to A<int*>::h() and A<float*>::h()
template<class T> template<T U> // grants friendship to instantiations of A<T>::i() and
friend T A<T>::i(); // to A<int>::i(), and thereby to all specializations
}; // of those function templates
— end example
template<class T> class A { };
class X {
template<class T> friend class A<T*>; // error
}; — end example
template<class T1, class T2, int I> class A { };
template<class T, int I> class A<T, T*, I> { };
template<class T1, class T2, int I> class A<T1*, T2, I> { };
template<class T> class A<int, T*, 5> { };
template<class T1, class T2, int I> class A<T1, T2*, I> { };
template<typename T> concept C = true;
template<typename T> struct X { };
template<typename T> struct X<T*> { }; // #1
template<C T> struct X<T> { }; // #2
template<class T> struct A {
struct C {
template<class T2> struct B { };
template<class T2> struct B<T2**> { }; // partial specialization #1
};
};
// partial specialization of A<T>::C::B<T2>
template<class T> template<class T2>
struct A<T>::C::B<T2*> { }; // #2
A<short>::C::B<int*> absip; // uses partial specialization #2
— end example
namespace N {
template<class T1, class T2> class A { }; // primary template
}
using N::A; // refers to the primary template
namespace N {
template<class T> class A<T, T*> { }; // partial specialization
}
A<int,int*> a; // uses the partial specialization, which is found through the using-declaration
// which refers to the primary template
— end example
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
— end example
template<class T1, class T2, int I> class A { }; // #1
template<class T, int I> class A<T, T*, I> { }; // #2
template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3
template<class T> class A<int, T*, 5> { }; // #4
template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5
A<int, int, 1> a1; // uses #1
A<int, int*, 1> a2; // uses #2, T is int, I is 1
A<int, char*, 5> a3; // uses #4, T is char
A<int, char*, 1> a4; // uses #5, T1 is int, T2 is char, I is 1
A<int*, int*, 2> a5; // ambiguous: matches #3 and #5
— end example
template<typename T> concept C = requires (T t) { t.f(); };
template<typename T> struct S { }; // #1
template<C T> struct S<T> { }; // #2
struct Arg { void f(); };
S<int> s1; // uses #1; the constraints of #2 are not satisfied
S<Arg> s2; // uses #2; both constraints are satisfied but #2 is more specialized
— end example
template <int I, int J> struct A {};
template <int I> struct A<I+5, I*2> {}; // error
template <int I> struct A<I, I> {}; // OK
template <int I, int J, int K> struct B {};
template <int I> struct B<I, I*2, 2> {}; // OK
— end example
template<int I, int J, class T> class X { };
template<int I, int J> class X<I, J, int> { }; // #1
template<int I> class X<I, I, int> { }; // #2
template<int I0, int J0> void f(X<I0, J0, int>); // A
template<int I0> void f(X<I0, I0, int>); // B
template <auto v> class Y { };
template <auto* p> class Y<p> { }; // #3
template <auto** pp> class Y<pp> { }; // #4
template <auto* p0> void g(Y<p0>); // C
template <auto** pp0> void g(Y<pp0>); // D
template<typename T> concept C = requires (T t) { t.f(); };
template<typename T> concept D = C<T> && requires (T t) { t.f(); };
template<typename T> class S { };
template<C T> class S<T> { }; // #1
template<D T> class S<T> { }; // #2
template<C T> void f(S<T>); // A
template<D T> void f(S<T>); // B
— end example// primary class template template<class T, int I> struct A { void f(); }; // member of primary class template template<class T, int I> void A<T,I>::f() { } // class template partial specialization template<class T> struct A<T,2> { void f(); void g(); void h(); }; // member of class template partial specialization template<class T> void A<T,2>::g() { } // explicit specialization template<> void A<char,2>::h() { } int main() { A<char,0> a0; A<char,2> a2; a0.f(); // OK, uses definition of primary template's member a2.g(); // OK, uses definition of partial specialization's member a2.h(); // OK, uses definition of explicit specialization's member a2.f(); // ill-formed, no definition of f for A<T,2>; the primary template is not used here }— end example
template<class T> struct A {
template<class T2> struct B {}; // #1
template<class T2> struct B<T2*> {}; // #2
};
template<> template<class T2> struct A<short>::B {}; // #3
A<char>::B<int*> abcip; // uses #2
A<short>::B<int*> absip; // uses #3
A<char>::B<int> abci; // uses #1
— end example
template<class T> class Array { };
template<class T> void sort(Array<T>&); — end example// translation unit 1: template<class T> void f(T*); void g(int* p) { f(p); // calls f<int>(int*) }
// translation unit 2: template<class T> void f(T); void h(int* p) { f(p); // calls f<int*>(int*) }
template<class T> void f(); template<int I> void f(); // OK: overloads the first template // distinguishable with an explicit template argument list— end note
template <int I, int J> A<I+J> f(A<I>, A<J>); // #1 template <int K, int L> A<K+L> f(A<K>, A<L>); // same as #1 template <int I, int J> A<I-J> f(A<I>, A<J>); // different from #1— end example
template <int I, int J> void f(A<I+J>); // #1 template <int K, int L> void f(A<K+L>); // same as #1 template <class T> decltype(g(T())) h(); int g(int); template <class T> decltype(g(T())) h() // redeclaration of h() uses the earlier lookup… { return g(T()); } // … although the lookup here does find g(int) int i = h<int>(); // template argument substitution fails; g(int) // was not in scope at the first declaration of h() // ill-formed, no diagnostic required: the two expressions are functionally equivalent but not equivalent template <int N> void foo(const char (*s)[([]{}, N)]); template <int N> void foo(const char (*s)[([]{}, N)]); // two different declarations because the non-dependent portions are not considered equivalent template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]); template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]);— end example
// guaranteed to be the same template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+10>); // guaranteed to be different template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+11>); // ill-formed, no diagnostic required template <int I> void f(A<I>, A<I+10>); template <int I> void f(A<I>, A<I+1+2+3+4>);— end note
struct A { };
template<class T> struct B {
template<class R> int operator*(R&); // #1
};
template<class T, class R> int operator*(T&, R&); // #2
// The declaration of B::operator* is transformed into the equivalent of
// template<class R> int operator*(B<A>&, R&); // #1a
int main() {
A a;
B<A> b;
b * a; // calls #1a
} — end example
template<class T> struct A { A(); };
template<class T> void f(T);
template<class T> void f(T*);
template<class T> void f(const T*);
template<class T> void g(T);
template<class T> void g(T&);
template<class T> void h(const T&);
template<class T> void h(A<T>&);
void m() {
const int* p;
f(p); // f(const T*) is more specialized than f(T) or f(T*)
float x;
g(x); // ambiguous: g(T) or g(T&)
A<int> z;
h(z); // overload resolution selects h(A<T>&)
const A<int> z2;
h(z2); // h(const T&) is called because h(A<T>&) is not callable
} — end exampletemplate<class T> void f(T); // #1 template<class T> void f(T*, int=1); // #2 template<class T> void g(T); // #3 template<class T> void g(T*, ...); // #4
int main() {
int* ip;
f(ip); // calls #2
g(ip); // calls #4
} — end example
template<class T, class U> struct A { };
template<class T, class U> void f(U, A<U, T>* p = 0); // #1
template< class U> void f(U, A<U, U>* p = 0); // #2
template<class T > void g(T, T = T()); // #3
template<class T, class... U> void g(T, U ...); // #4
void h() {
f<int>(42, (A<int, int>*)0); // calls #2
f<int>(42); // error: ambiguous
g(42); // error: ambiguous
} — end exampletemplate<class T, class... U> void f(T, U...); // #1 template<class T > void f(T); // #2 template<class T, class... U> void g(T*, U...); // #3 template<class T > void g(T); // #4 void h(int i) { f(&i); // error: ambiguous g(&i); // OK: calls #3 }— end example
template<class T> struct Alloc { /* ... */ };
template<class T> using Vec = vector<T, Alloc<T>>;
Vec<int> v; // same as vector<int, Alloc<int>> v;
template<class T>
void process(Vec<T>& v)
{ /* ... */ }
template<class T>
void process(vector<T, Alloc<T>>& w)
{ /* ... */ } // error: redefinition
template<template<class> class TT>
void f(TT<int>);
f(v); // error: Vec not deduced
template<template<class,class> class TT>
void g(TT<int, Alloc<int>>);
g(v); // OK: TT = vector
— end example
template<typename...> using void_t = void;
template<typename T> void_t<typename T::foo> f();
f<int>(); // error, int does not have a nested type foo
— end example
template <class T> struct A;
template <class T> using B = typename A<T>::U;
template <class T> struct A {
typedef B<T> U;
};
B<short> b; // error: instantiation of B<short> uses own type via A<short>::U
— end example
template <class T>
using A = decltype([] { }); // A<int> and A<char> refer to different closure types
— end example
template<typename T>
concept C = requires(T x) {
{ x == x } -> bool;
};
template<typename T>
requires C<T> // C constrains f1(T) in constraint-expression
T f1(T x) { return x; }
template<C T> // C constrains f2(T) as a constrained-parameter
T f2(T x) { return x; } — end example// no B declared here class X; template<class T> class Y { class Z; // forward declaration of member class void f() { X* a1; // declare pointer to X T* a2; // declare pointer to T Y* a3; // declare pointer to Y<T> Z* a4; // declare pointer to Z typedef typename T::A TA; TA* a5; // declare pointer to T's A typename T::A* a6; // declare pointer to T's A T::A* a7; // T::A is not a type name: // multiplication of T::A by a7; ill-formed, no visible declaration of a7 B* a8; // B is not a type name: // multiplication of B by a8; ill-formed, no visible declarations of B and a8 } };— end example
typename-specifier: typename nested-name-specifier identifier typename nested-name-specifier template simple-template-id
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); // OK: T::X refers to B::X
f(a); // error: T::X refers to the data member A::X not the struct A::X
} — end exampletemplate<class T> T::R f(); // OK, return type of a function declaration at global scope template<class T> void f(T::R); // ill-formed (no diagnostic required), attempt to declare // a void variable template template<class T> struct S { using Ptr = PtrTraits<T>::Ptr; // OK, in a defining-type-id T::R f(T::P p) { // OK, class scope return static_cast<T::R>(p); // OK, type-id of a static_cast } auto g() -> S<T*>::Ptr; // OK, trailing-return-type }; template<typename T> void f() { void (*pf)(T::X); // variable pf of type void* initialized with T::X void g(T::X); // error: T::X at block scope does not denote a type // (attempt to declare a void variable) }— end example
template <class T> void f(int i) {
T::x * i; // expression, not the declaration of a variable i
}
struct Foo {
typedef int x;
};
struct Bar {
static int const x = 5;
};
int main() {
f<Bar>(1); // OK
f<Foo>(1); // error: Foo::x is a type
} — end example
template<class T> struct A {
typedef int B;
B b; // OK, no typename required
}; — end example
int j;
template<class T> class X {
void f(T t, int i, char* p) {
t = i; // diagnosed if X::f is instantiated, and the assignment to t is an error
p = i; // may be diagnosed even if X::f is not instantiated
p = j; // may be diagnosed even if X::f is not instantiated
}
void g(T t) {
+; // may be diagnosed even if X::g is not instantiated
}
};
template<class... T> struct A {
void operator++(int, T... t); // error: too many parameters
};
template<class... T> union X : T... { }; // error: union with base class
template<class... T> struct A : T..., T... { }; // error: duplicate base class
— end example
#include <iostream>
using namespace std;
template<class T> class Set {
T* p;
int cnt;
public:
Set();
Set<T>(const Set<T>&);
void printall() {
for (int i = 0; i<cnt; i++)
cout << p[i] << '\n';
}
};
void f(char);
template<class T> void g(T t) {
f(1); // f(char)
f(T(1)); // dependent
f(t); // dependent
dd++; // not dependent; error: declaration for dd not found
}
enum E { e };
void f(E);
double dd;
void h() {
g(e); // will cause one call of f(char) followed by two calls of f(E)
g('a'); // will cause three calls of f(char)
} — end example
template<template<class> class T> class A { };
template<class T> class Y;
template<> class Y<int> {
Y* p; // meaning Y<int>
Y<char>* q; // meaning Y<char>
A<Y>* a; // meaning A<::Y>
class B {
template<class> friend class Y; // meaning ::Y
};
}; — end example
template <class T> struct Base {
Base* p;
};
template <class T> struct Derived: public Base<T> {
typename Derived::Base* p; // meaning Derived::Base<T>
};
template<class T, template<class> class U = T::template Base> struct Third { };
Third<Derived<int> > t; // OK: default argument uses injected-class-name as a template
— end 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
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
template<class T, int i> class Y {
int T; // error: template-parameter redeclared
void f() {
char T; // error: template-parameter redeclared
}
};
template<class X> class X; // error: template-parameter redeclared
— end example
template<class T> struct A {
struct B { /* ... */ };
typedef void C;
void f();
template<class U> void g(U);
};
template<class B> void A<B>::f() {
B b; // A's B, not the template parameter
}
template<class B> template<class C> void A<B>::g(C) {
B b; // A's B, not the template parameter
C c; // the template parameter C, not A's C
} — end example
namespace N {
class C { };
template<class T> class B {
void f(T);
};
}
template<class C> void N::B<C>::f(C) {
C b; // C is the template parameter, not N::C
} — end example
struct A {
struct B { /* ... */ };
int a;
int Y;
};
template<class B, class a> struct X : A {
B b; // A's B
a b; // error: A's a isn't a type name
}; — end examplepostfix-expression ( expression-list )
template<class T> struct X : B<T> {
typename T::A* pa;
void f(B<T>* pb) {
static int i = B<T>::i;
pb->j++;
}
};
typedef double A;
template<class T> class B {
typedef int A;
};
template<class T> struct X : B<T> {
A a; // a has type double
};
struct A {
struct B { /* ... */ };
int a;
int Y;
};
int a;
template<class T> struct Y : T {
struct B { /* ... */ };
B b; // The B defined in Y
void f(int i) { a = i; } // ::a
Y* p; // Y<T>
};
Y<A> ya;
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;
static const long my_I4 = I;
static const int my_I5 = (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
B<my_T1, T2, my_I4>* b6; // not the current instantiation
B<my_T1, T2, my_I5>* b7; // not the current instantiation
}; — end example
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; // OK, A<T>::M
}; — end 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
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
struct A {
int m;
};
struct B {
int m;
};
template<typename T>
struct C : A, T {
int f() { return this->m; } // finds A::m in the template definition context
int g() { return m; } // finds A::m in the template definition context
};
template int C<B>::f(); // error: finds both A::m and B::m
template int C<B>::g(); // OK: transformation to class member access syntax
// does not occur in the template definition context; see [class.mfct.non-static]
— end examplesimple-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
literal postfix-expression . pseudo-destructor-name postfix-expression -> pseudo-destructor-name sizeof unary-expression sizeof ( type-id ) sizeof ... ( identifier ) alignof ( type-id ) typeid ( expression ) typeid ( type-id ) :: delete cast-expression :: delete [ ] cast-expression throw assignment-expression noexcept ( expression )
sizeof unary-expression sizeof ( type-id ) typeid ( expression ) typeid ( type-id ) alignof ( type-id ) noexcept ( expression )
simple-type-specifier ( expression-list ) static_cast < type-id > ( expression ) const_cast < type-id > ( expression ) reinterpret_cast < type-id > ( expression ) ( type-id ) cast-expression
void g(double);
void h();
template<class T> class Z {
public:
void f() {
g(1); // calls g(double)
h++; // ill-formed: cannot increment function; this could be diagnosed
// either here or at the point of instantiation
}
};
void g(int); // not in scope at the point of the template definition, not considered for the call g(1)
— end example
template<typename T> struct number {
number(int);
friend number gcd(number x, number y) { return 0; };
};
void g() {
number<double> a(3), b(4);
a = gcd(a,b); // finds gcd because number<double> is an associated class,
// making gcd visible in its namespace (global scope)
b = gcd(3,4); // ill-formed; gcd is not visible
} — end example
template<class T = int> struct A {
static int x;
};
template<class U> void g(U) { }
template<> struct A<double> { }; // specialize for T == double
template<> struct A<> { }; // specialize for T == int
template<> void g(char) { } // specialize for U == char
// U is deduced from the parameter type
template<> void g<int>(int) { } // specialize for U == int
template<> int A<char>::x = 0; // specialize for T == char
template<class T = int> struct B {
static int x;
};
template<> int B<>::x = 1; // specialize for T == int
— end example
template<class T> struct A {
static T t;
};
typedef int function();
A<function> a; // ill-formed: would declare A<function>::t as a static member function
— end example
template<class T> class B { /* ... */ };
template<class T> class D : public B<T> { /* ... */ };
void f(void*);
void f(B<int>*);
void g(D<int>* p, D<char>* pp, D<double>* ppp) {
f(p); // instantiation of D<int> required: call f(B<int>*)
B<char>* q = pp; // instantiation of D<char> required: convert D<char>* to B<char>*
delete ppp; // instantiation of D<double> required
} — end example
template<class T>
struct C {
void f() { T x; }
void g() = delete;
};
C<void> c; // OK, definition of C<void>::f is not instantiated at this point
template<> void C<int>::g() { } // error: redefinition of C<int>::g
— end example
template<class T, class U>
struct Outer {
template<class X, class Y> struct Inner;
template<class Y> struct Inner<T, Y>; // #1a
template<class Y> struct Inner<T, Y> { }; // #1b; OK: valid redeclaration of #1a
template<class Y> struct Inner<U, Y> { }; // #2
};
Outer<int, int> outer; // error at #2
template<typename T> struct Friendly {
template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff; // ill-formed: produces second definition of f(U)
— end example
template<class T> struct Z {
void f();
void g();
};
void h() {
Z<int> a; // instantiation of class Z<int> required
Z<char>* p; // instantiation of class Z<char> not required
Z<double>* q; // instantiation of class Z<double> not required
a.f(); // instantiation of Z<int>::f() required
p->g(); // instantiation of class Z<char> required, and
// instantiation of Z<char>::g() required
}
template<typename T> constexpr int f() { return T::value; }
template<bool B, typename T> void g(decltype(B ? f<T>() : 0));
template<bool B, typename T> void g(...);
template<bool B, typename T> void h(decltype(int{B ? f<T>() : 0}));
template<bool B, typename T> void h(...);
void x() {
g<false, int>(0); // OK, B ? f<T>() : 0 is not potentially constant evaluated
h<false, int>(0); // error, instantiates f<int> even though B evaluates to false and
// list-initialization of int from int cannot be narrowing
} — end example
template <class T> struct S {
operator int();
};
void f(int);
void f(S<int>&);
void f(S<float>);
void g(S<int>& sr) {
f(sr); // instantiation of S<int> allowed but not required
// instantiation of S<float> allowed but not required
}; — end example
namespace N {
template<class T> class List {
public:
T* get();
};
}
template<class K, class V> class Map {
public:
N::List<V> lt;
V get(K);
};
void g(Map<const char*,int>& m) {
int i = m.get("Nicholas");
}
template<class T> void f(T x, T y = ydef(T()), T z = zdef(T()));
class A { };
A zdef(A);
void g(A a, A b, A c) {
f(a, b, c); // no default argument instantiation
f(a, b); // default argument z = zdef(T()) instantiated
f(a); // ill-formed; ydef is not declared
} — end example
template<class T> class X {
X<T>* p; // OK
X<T*> a; // implicit generation of X<T> requires
// the implicit instantiation of X<T*> which requires
// the implicit instantiation of X<T**> which …
}; — end example
template<typename T> concept C = sizeof(T) > 2;
template<typename T> concept D = C<T> && sizeof(T) > 4;
template<typename T> struct S {
S() requires C<T> { } // #1
S() requires D<T> { } // #2
};
S<char> s1; // error: no matching constructor
S<char[8]> s2; // OK, calls #2
template<typename T> struct S1 {
template<typename U>
requires false
struct Inner1; // ill-formed, no diagnostic required
};
template<typename T> struct S2 {
template<typename U>
requires (sizeof(T[-(int)sizeof(T)]) > 1)
struct Inner2; // ill-formed, no diagnostic required
}; explicit-instantiation: extern template declaration
template<class T> class Array { void mf(); };
template class Array<char>;
template void Array<int>::mf();
template<class T> void sort(Array<T>& v) { /* ... */ }
template void sort(Array<char>&); // argument is deduced here
namespace N {
template<class T> void f(T&) { }
}
template void N::f<int>(int&); — end example
template<typename T> T var = {};
template float var<float>; // OK, instantiated variable has type float
template int var<int[16]>[]; // OK, absence of major array bound is permitted
template int *var<int>; // error: instantiated variable has type int
template<typename T> auto av = T();
template int av<int>; // OK, variable with type int can be redeclared with type auto
template<typename T> auto f() {}
template void f<int>(); // error: function with deduced return type
// redeclared with non-deduced return type ([dcl.spec.auto])
— end example
namespace N {
template<class T> class Y { void mf() { } };
}
template class Y<int>; // error: class template Y not visible in the global namespace
using N::Y;
template class Y<int>; // error: explicit instantiation outside of the namespace of the template
template class N::Y<char*>; // OK: explicit instantiation in namespace N
template void N::Y<double>::mf(); // OK: explicit instantiation in namespace N
— end example
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
// instantiate sort(Array<int>&) – template-argument deduced
template void sort<>(Array<int>&); — end exampleexplicit-specialization: template < > declaration
template<class T> class stream;
template<> class stream<char> { /* ... */ };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
template<> void sort<char*>(Array<char*>&);
template<> class X<int> { /* ... */ }; // error: X not a template
template<class T> class X;
template<> class X<char*> { /* ... */ }; // OK: X is a template
— end example
template<class T> struct A {
struct B { };
template<class U> struct C { };
};
template<> struct A<int> {
void f(int);
};
void h() {
A<int> a;
a.f(16); // A<int>::f must be defined somewhere
}
// template<> not used for a member of an explicitly specialized class template
void A<int>::f(int) { /* ... */ }
template<> struct A<char>::B {
void f();
};
// template<> also not used when defining a member of an explicitly specialized member class
void A<char>::B::f() { /* ... */ }
template<> template<class U> struct A<char>::C {
void f();
};
// template<> is used when defining a member of an explicitly specialized member class template
// specialized as a class template
template<>
template<class U> void A<char>::C<U>::f() { /* ... */ }
template<> struct A<short>::B {
void f();
};
template<> void A<short>::B::f() { /* ... */ } // error: template<> not permitted
template<> template<class U> struct A<short>::C {
void f();
};
template<class U> void A<short>::C<U>::f() { /* ... */ } // error: template<> required
— end example
class String { };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
void f(Array<String>& v) {
sort(v); // use primary template sort(Array<T>&), T is String
}
template<> void sort<String>(Array<String>& v); // error: specialization after use of primary template
template<> void sort<>(Array<char*>& v); // OK: sort<char*> not yet used
template<class T> struct A {
enum E : T;
enum class S : T;
};
template<> enum A<int>::E : int { eint }; // OK
template<> enum class A<int>::S : int { sint }; // OK
template<class T> enum A<T>::E : T { eT };
template<class T> enum class A<T>::S : T { sT };
template<> enum A<char>::E : char { echar }; // ill-formed, A<char>::E was instantiated
// when A<char> was instantiated
template<> enum class A<char>::S : char { schar }; // OK
— end example
namespace N {
template<class T> class X { /* ... */ };
template<class T> class Y { /* ... */ };
template<> class X<int> { /* ... */ }; // OK: specialization in same namespace
template<> class Y<double>; // forward-declare intent to specialize for double
}
template<> class N::Y<double> { /* ... */ }; // OK: specialization in enclosing namespace
template<> class N::Y<short> { /* ... */ }; // OK: specialization in enclosing namespace
— end exampletemplate<class T> class X; // X is a class template template<> class X<int>; X<int>* p; // OK: pointer to declared class X<int> X<int> x; // error: object of incomplete class X<int>— end example
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v);
// explicit specialization for sort(Array<int>&)
// with deduced template-argument of type int
template<> void sort(Array<int>&); — end example
template<class T> void f(T) { /* ... */ }
template<class T> inline T g(T) { /* ... */ }
template<> inline void f<>(int) { /* ... */ } // OK: inline
template<> int g<>(int) { /* ... */ } // OK: not inline
— end exampletemplate<> X Q<int>::x; // declaration template<> X Q<int>::x (); // error: declares a function template<> X Q<int>::x { }; // definition— end note
template<class T> struct A {
void f(T);
template<class X1> void g1(T, X1);
template<class X2> void g2(T, X2);
void h(T) { }
};
// specialization
template<> void A<int>::f(int);
// out of class member template definition
template<class T> template<class X1> void A<T>::g1(T, X1) { }
// member template specialization
template<> template<class X1> void A<int>::g1(int, X1);
// member template specialization
template<> template<>
void A<int>::g1(int, char); // X1 deduced as char
template<> template<>
void A<int>::g2<char>(int, char); // X2 specified as char
// member specialization even if defined in class definition
template<> void A<int>::h(int) { } — end example
template<class T1> class A {
template<class T2> class B {
void mf();
};
};
template<> template<> class A<int>::B<double>;
template<> template<> void A<char>::B<char>::mf(); — end example
template <class T1> class A {
template<class T2> class B {
template<class T3> void mf1(T3);
void mf2();
};
};
template <> template <class X>
class A<int>::B {
template <class T> void mf1(T);
};
template <> template <> template<class T>
void A<int>::B<double>::mf1(T t) { }
template <class Y> template <>
void A<Y>::B<double>::mf2() { } // ill-formed; B<double> is specialized but
// its enclosing class template A is not
— end example
template<class T> void sort(Array<T>& v);
void f(Array<dcomplex>& cv, Array<int>& ci) {
sort<dcomplex>(cv); // sort(Array<dcomplex>&)
sort<int>(ci); // sort(Array<int>&)
}
template<class U, class V> U convert(V v);
void g(double d) {
int i = convert<int,double>(d); // int convert(double)
char c = convert<char,double>(d); // char convert(double)
}
template<class X, class Y> X f(Y);
template<class X, class Y, class ... Z> X g(Y);
void h() {
int i = f<int>(5.6); // Y is deduced to be double
int j = f(5.6); // ill-formed: X cannot be deduced
f<void>(f<int, bool>); // Y for outer f deduced to be int (*)(bool)
f<void>(f<int>); // ill-formed: f<int> does not denote a single function template specialization
int k = g<int>(5.6); // Y is deduced to be double, Z is deduced to an empty sequence
f<void>(g<int, bool>); // Y for outer f is deduced to be int (*)(bool),
// Z is deduced to an empty sequence
} — end exampletemplate <class T> int f(T); // #1 int f(int); // #2 int k = f(1); // uses #2 int l = f<>(1); // uses #1— end note
template<class X, class Y, class Z> X f(Y,Z);
template<class ... Args> void f2();
void g() {
f<int,const char*,double>("aa",3.0);
f<int,const char*>("aa",3.0); // Z is deduced to be double
f<int>("aa",3.0); // Y is deduced to be const char*, and Z is deduced to be double
f("aa",3.0); // error: X cannot be deduced
f2<char, short, int, long>(); // OK
} — end example
template<class ... Types> void f(Types ... values);
void g() {
f<int*, float*>(0, 0, 0); // Types is deduced to the sequence int*, float*, int
} — end example
void f(Array<dcomplex>& cv, Array<int>& ci) {
sort(cv); // calls sort(Array<dcomplex>&)
sort(ci); // calls sort(Array<int>&)
}
void g(double d) {
int i = convert<int>(d); // calls convert<int,double>(double)
int c = convert<char>(d); // calls convert<char,double>(double)
}
template <class T> void f(T t);
template <class X> void g(const X x);
template <class Z> void h(Z, Z*);
int main() {
// #1: function type is f(int), t is non const
f<int>(1);
// #2: function type is f(int), t is const
f<const int>(1);
// #3: function type is g(int), x is const
g<int>(1);
// #4: function type is g(int), x is const
g<const int>(1);
// #5: function type is h(int, const int*)
h<const int>(1,0);
} — end example
template <class T, class U = double>
void f(T t = 0, U u = 0);
void g() {
f(1, 'c'); // f<int,char>(1,'c')
f(1); // f<int,double>(1,0)
f(); // error: T cannot be deduced
f<int>(); // f<int,double>(0,0)
f<int,char>(); // f<int,char>(0,0)
} — end example
template <class T> struct A { using X = typename T::X; };
template <class T> typename T::X f(typename A<T>::X);
template <class T> void f(...) { }
template <class T> auto g(typename A<T>::X) -> typename T::X;
template <class T> void g(...) { }
template <class T> typename T::X h(typename A<T>::X);
template <class T> auto h(typename A<T>::X) -> typename T::X; // redeclaration
template <class T> void h(...) { }
void x() {
f<int>(0); // OK, substituting return type causes deduction to fail
g<int>(0); // error, substituting parameter type instantiates A<int>
h<int>(0); // ill-formed, no diagnostic required
} — end example
template <class T>
auto f(T) -> decltype([]() { T::invalid; } ());
void f(...);
f(0); // error: invalid expression not part of the immediate context
template <class T, std::size_t = sizeof([]() { T::invalid; })>
void g(T);
void g(...);
g(0); // error: invalid expression not part of the immediate context
template <class T>
auto h(T) -> decltype([x = T::invalid]() { });
void h(...);
h(0); // error: invalid expression not part of the immediate context
template <class T>
auto i(T) -> decltype([]() -> typename T::invalid { });
void i(...);
i(0); // error: invalid expression not part of the immediate context
template <class T>
auto j(T t) -> decltype([](auto x) -> decltype(x.invalid) { } (t)); // #1
void j(...); // #2
j(0); // deduction fails on #1, calls #2
— end example
struct X { };
struct Y {
Y(X){}
};
template <class T> auto f(T t1, T t2) -> decltype(t1 + t2); // #1
X f(Y, Y); // #2
X x1, x2;
X x3 = f(x1, x2); // deduction fails on #1 (cannot add X+X), calls #2
— end example
template <class T> int f(T[5]);
int I = f<int>(0);
int j = f<void>(0); // invalid array
— end example
template <int I> struct X { };
template <template <class T> class> struct Z { };
template <class T> void f(typename T::Y*){}
template <class T> void g(X<T::N>*){}
template <class T> void h(Z<T::template TT>*){}
struct A {};
struct B { int Y; };
struct C {
typedef int N;
};
struct D {
typedef int TT;
};
int main() {
// Deduction fails in each of these cases:
f<A>(0); // A does not contain a member Y
f<B>(0); // The Y member of B is not a type
g<C>(0); // The N member of C is not a non-type
h<D>(0); // The TT member of D is not a template
} — end example
template <class T, T> struct S {};
template <class T> int f(S<T, T()>*);
struct X {};
int i0 = f<X>(0); — end example
template <class T, T*> int f(int);
int i2 = f<int,1>(0); // can't conv 1 to int*
— end exampletemplate <int> int f(int); template <signed char> int f(int); int i1 = f<1000>(0); // OK int i2 = f<1>(0); // ambiguous; not narrowing— end example
template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
f({1,"asdf"}); // error: T deduced to both int and const char*
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
template<class T, int N> void h(T const(&)[N]);
h({1,2,3}); // T deduced to int, N deduced to 3
template<class T> void j(T const(&)[3]);
j({42}); // T deduced to int, array bound not considered
struct Aggr { int i; int j; };
template<int N> void k(Aggr const(&)[N]);
k({1,2,3}); // error: deduction fails, no conversion from int to Aggr
k({{1},{2},{3}}); // OK, N deduced to 3
template<int M, int N> void m(int const(&)[M][N]);
m({{1,2},{3,4}}); // M and N both deduced to 2
template<class T, int N> void n(T const(&)[N], T);
n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
— end example
template<class ... Types> void f(Types& ...);
template<class T1, class ... Types> void g(T1, Types ...);
template<class T1, class ... Types> void g1(Types ..., T1);
void h(int x, float& y) {
const int z = x;
f(x, y, z); // Types is deduced to int, float, const int
g(x, y, z); // T1 is deduced to int; Types is deduced to float, int
g1(x, y, z); // error: Types is not deduced
g1<int, int, int>(x, y, z); // OK, no deduction occurs
} — end exampletemplate<class T> int f(const T&); int n1 = f(5); // calls f<int>(const int&) const int i = 0; int n2 = f(i); // calls f<int>(const int&) template <class T> int g(volatile T&); int n3 = g(i); // calls g<const int>(const volatile int&)— end example
template <class T> int f(T&& heisenreference); template <class T> int g(const T&&); int i; int n1 = f(i); // calls f<int&>(int&) int n2 = f(0); // calls f<int>(int&&) int n3 = g(i); // error: would call g<int>(const int&&), which // would bind an rvalue reference to an lvalue template <class T> struct A { template <class U> A(T&&, U&&, int*); // #1: T&& is not a forwarding reference. // U&& is a forwarding reference. A(T&&, int*); // #2 }; template <class T> A(T&&, int*) -> A<T>; // #3: T&& is a forwarding reference. int *ip; A a{i, 0, ip}; // error: cannot deduce from #1 A a0{0, 0, ip}; // uses #1 to deduce A<int> and #1 to initialize A a2{i, ip}; // uses #3 to deduce A<int&> and #2 to initialize— end example
// Only one function of an overload set matches the call so the function parameter is a deduced context. template <class T> int f(T (*p)(T)); int g(int); int g(char); int i = f(g); // calls f(int (*)(int))— end example
// Ambiguous deduction causes the second function parameter to be a non-deduced context. template <class T> int f(T, T (*p)(T)); int g(int); char g(char); int i = f(1, g); // calls f(int, int (*)(int))— end example
// The overload set contains a template, causing the second function parameter to be a non-deduced context. template <class T> int f(T, T (*p)(T)); char g(char); template <class T> T g(T); int i = f(1, g); // calls f(int, int (*)(int))— end example
template <class T> struct Z {
typedef typename T::x xx;
};
template <class T> typename Z<T>::xx f(void *, T); // #1
template <class T> void f(int, T); // #2
struct A {} a;
int main() {
f(1, a); // OK, deduction fails for #1 because there is no conversion from int to void*
} — end example
struct A {
template <class T> operator T***();
};
A a;
const int * const * const * p1 = a; // T is deduced as int, not const int
— end exampletemplate<class... Args> void f(Args... args); // #1 template<class T1, class... Args> void f(T1 a1, Args... args); // #2 template<class T1, class T2> void f(T1 a1, T2 a2); // #3 f(); // calls #1 f(1, 2, 3); // calls #2 f(1, 2); // calls #3; non-variadic template #3 is more specialized // than the variadic templates #1 and #2— end example
template <class T> T f(int); // #1 template <class T, class U> T f(U); // #2 void g() { f<int>(1); // calls #1 }— end example
template<class ...> struct Tuple { };
template<class ... Types> void g(Tuple<Types ...>); // #1
template<class T1, class ... Types> void g(Tuple<T1, Types ...>); // #2
template<class T1, class ... Types> void g(Tuple<T1, Types& ...>); // #3
g(Tuple<>()); // calls #1
g(Tuple<int, float>()); // calls #2
g(Tuple<int, float&>()); // calls #3
g(Tuple<int>()); // calls #3
— end example
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
— end example
template<class T> void f(T x, T y) { /* ... */ }
struct A { /* ... */ };
struct B : A { /* ... */ };
void g(A a, B b) {
f(a,b); // error: T could be A or B
f(b,a); // error: T could be A or B
f(a,a); // OK: T is A
f(b,b); // OK: T is B
}
template <class T, class U> void f( T (*)( T, U, U ) );
int g1( int, float, float);
char g2( int, float, float);
int g3( int, char, float);
void r() {
f(g1); // OK: T is int and U is float
f(g2); // error: T could be char or int
f(g3); // error: U could be char or float
}
template<class T> void f(const T*) { }
int* p;
void s() {
f(p); // f(const int*)
}
template <class T> struct B { };
template <class T> struct D : public B<T> {};
struct D2 : public B<int> {};
template <class T> void f(B<T>&){}
void t() {
D<int> d;
D2 d2;
f(d); // calls f(B<int>&)
f(d2); // calls f(B<int>&)
} — end exampleT cv T T* T& T&& T[integer-constant] template-name<T> (where template-name refers to a class template) type(T) T() T(T) T type::* type T::* T T::* T (type::*)() type (T::*)() type (type::*)(T) type (T::*)(T) T (type::*)(T) T (T::*)() T (T::*)(T) type[i] template-name<i> (where template-name refers to a class template) TT<T> TT<i> TT<>
template<class T1, class... Z> class S; // #1 template<class T1, class... Z> class S<T1, const Z&...> { }; // #2 template<class T1, class T2> class S<T1, const T2&> { }; // #3 S<int, const int&> s; // both #2 and #3 match; #3 is more specialized template<class T, class... U> struct A { }; // #1 template<class T1, class T2, class... U> struct A<T1, T2*, U...> { }; // #2 template<class T1, class T2> struct A<T1, T2> { }; // #3 template struct A<int, int*>; // selects #2— end example
template <class T> void f(T&&);
template <> void f(int&) { } // #1
template <> void f(int&&) { } // #2
void g(int i) {
f(i); // calls f<int&>(int&), i.e., #1
f(0); // calls f<int>(int&&), i.e., #2
} — end example
template<class T, class... U> void f(T*, U...) { } // #1
template<class T> void f(T) { } // #2
template void f(int*); // selects #1
— end example
template<long n> struct A { };
template<typename T> struct C;
template<typename T, T n> struct C<A<n>> {
using Q = T;
};
using R = long;
using R = C<A<2>>::Q; // OK; T was deduced to long from the
// template argument value in the type A<2>
— end example
template<typename T> struct S;
template<typename T, T n> struct S<int[n]> {
using Q = T;
};
using V = decltype(sizeof 0);
using V = S<int[42]>::Q; // OK; T was deduced to std::size_t from the type int[42]
— end example
template<class T, T i> void f(int (&a)[i]);
int v[10];
void g() {
f(v); // OK: T is std::size_t
} — end example
template<int i> void f1(int a[10][i]);
template<int i> void f2(int a[i][20]);
template<int i> void f3(int (&a)[i][20]);
void g() {
int v[10][20];
f1(v); // OK: i deduced to be 20
f1<20>(v); // OK
f2(v); // error: cannot deduce template-argument i
f2<10>(v); // OK
f3(v); // OK: i deduced to be 10
}
template <int i> class A { /* ... */ };
template <int i> void g(A<i+1>);
template <int i> void f(A<i>, A<i+1>);
void k() {
A<1> a1;
A<2> a2;
g(a1); // error: deduction fails for expression i+1
g<0>(a1); // OK
f(a1, a2); // OK
} — end exampletemplate<int i, typename T> T deduce(typename A<T>::X x, // T is not deduced here T t, // but T is deduced here typename B<i>::Y y); // i is not deduced here A<int> a; B<77> b; int x = deduce<77>(a.xm, 62, b.ym); // T is deduced to be int, a.xm must be convertible to A<int>::X // i is explicitly specified to be 77, b.ym must be convertible to B<77>::Y— end note
template<int i> class A { /* ... */ };
template<short s> void f(A<s>);
void k1() {
A<1> a;
f(a); // error: deduction fails for conversion from int to short
f<1>(a); // OK
}
template<const short cs> class B { };
template<short s> void g(B<s>);
void k2() {
B<1> b;
g(b); // OK: cv-qualifiers are ignored on template parameter types
} — end example
template<class T> void f(void(*)(T,int));
template<class T> void foo(T,int);
void g(int,int);
void g(char,int);
void h(int,int,int);
void h(char,int);
int m() {
f(&g); // error: ambiguous
f(&h); // OK: void h(char,int) is a unique match
f(&foo); // error: type deduction fails because foo is a template
} — end example
template <class T> void f(T = 5, T = 7);
void g() {
f(1); // OK: call f<int>(1,7)
f(); // error: cannot deduce T
f<int>(); // OK: call f<int>(5,7)
} — end example
template <template <class T> class X> struct A { };
template <template <class T> class X> void f(A<X>) { }
template<class T> struct B { };
A<B> ab;
f(ab); // calls f(A<B>)
— end example
template<class> struct X { };
template<class R, class ... ArgTypes> struct X<R(int, ArgTypes ...)> { };
template<class ... Types> struct Y { };
template<class T, class ... Types> struct Y<T, Types& ...> { };
template<class ... Types> int f(void (*)(Types ...));
void g(int, float);
X<int> x1; // uses primary template
X<int(int, float, double)> x2; // uses partial specialization; ArgTypes contains float, double
X<int(float, int)> x3; // uses primary template
Y<> y1; // use primary template; Types is empty
Y<int&, float&, double&> y2; // uses partial specialization; T is int&, Types contains float, double
Y<int, float, double> y3; // uses primary template; Types contains int, float, double
int fv = f(g); // OK; Types contains int, float
— end example
template<class T> T max(T a, T b) { return a>b?a:b; }
void f(int a, int b, char c, char d) {
int m1 = max(a,b); // max(int a, int b)
char m2 = max(c,d); // max(char a, char b)
int m3 = max(a,c); // error: cannot generate max(int,char)
}int max(int,int);
template<class T> struct B { /* ... */ };
template<class T> struct D : public B<T> { /* ... */ };
template<class T> void f(B<T>&);
void g(B<int>& bi, D<int>& di) {
f(bi); // f(bi)
f(di); // f((B<int>&)di)
}template<class T> void f(T*,int); // #1 template<class T> void f(T,char); // #2 void h(int* pi, int i, char c) { f(pi,i); // #1: f<int>(pi,i) f(pi,c); // #2: f<int*>(pi,c) f(i,c); // #2: f<int>(i,c); f(i,i); // #2: f<int>(i,char(i)) }
template<class T> void f(T); // declaration void g() { f("Annemarie"); // call of f<const char*> }
deduction-guide: explicit template-name ( parameter-declaration-clause ) -> simple-template-id ;
template<class T, class D = int>
struct S {
T data;
};
template<class U>
S(U) -> S<typename U::type>;
struct A {
using type = short;
operator type();
};
S x{A()}; // x is of type S<short, int>
— end example