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