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]; } };
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> // ill-formed, 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
deduction-guide: explicit-specifier 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
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
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 example
template<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);
Operator | Value when pack is empty |
&& | true |
|| | false |
, | void() |
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(); // error: 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(); // error: 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 #1 }— 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 example
template<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 example
template<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); // OK: calls #2 g(&i); // OK: calls #3 }— end example
template <typename> constexpr bool True = true; template <typename T> concept C = True<T>; void f(C auto &, auto &) = delete; template <C Q> void f(Q &, C auto &); void g(struct A *ap, struct B *bp) { f(*ap, *bp); // OK: Can use different methods to produce template parameters } template <typename T, typename U> struct X {}; template <typename T, C U, typename V> bool operator==(X<T, U>, V) = delete; template <C T, C U, C V> bool operator==(T, X<U, V>); void h() { X<void *, int>{} == 0; // OK: Correspondence of [T, U, V] and [U, V, T] }— 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