C++ Tutorial/template/template parameter
Содержание
- 1 Default template arguments
- 2 Define implicit_cast
- 3 Demonstrate non-type template arguments
- 4 Loop with generic parameter
- 5 Nested template type
- 6 primary template to compute sqrt(N) via iteration and partial specialization to end the iteration
- 7 primary template: yield second or third argument depending on first argument
- 8 Sqrt: primary template: yield second or third argument depending on first argument
- 9 template function for generic parameter and pointer to generic parameter
- 10 Use template parameter as constructor parameter
Default template arguments
<source lang="cpp">#include <iostream>
- include <cstdlib>
using namespace std; // T defaults to int and size defaults to 10 template <class T=int, int size=10> class MyType {
T a[size];
public:
MyType() { for(int i=0; i<size; i++) a[i] = i; } T &operator[](int i){ if(i<0 || i> size-1) { cout << "\nIndex value of "; cout << i << " is out-of-bounds.\n"; exit(1); } return a[i]; }
};
int main() {
MyType<int, 100> intarray; MyType<double> doublearray; MyType<> defarray; cout << "int array: "; for(int i=0; i<100; i++) intarray[i] = i; for(int i=0; i<100; i++) cout << intarray[i] << " "; cout << "\n"; cout << "double array: "; for(int i=0; i<10; i++) doublearray[i] = (double) i/3; for(int i=0; i<10; i++) cout << doublearray[i] << " "; cout << "\n"; cout << "defarray array: "; for(int i=0; i<10; i++) defarray[i] = i; for(int i=0; i<10; i++) cout << defarray[i] << " "; cout << "\n"; return 0;
}</source>
int array: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 double array: 0 0.333333 0.666667 1 1.33333 1.66667 2 2.33333 2.66667 3 defarray array: 0 1 2 3 4 5 6 7 8 9
Define implicit_cast
<source lang="cpp">/* The following code example is taken from the book
* "C++ Templates - The Complete Guide" * by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002 * * (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. */
template <typename DstT, typename SrcT> inline DstT implicit_cast (SrcT const& x) // SrcT can be deduced, { // but DstT cannot
return x;
} int main() {
double value = implicit_cast<double>(-1);
}</source>
Demonstrate non-type template arguments
<source lang="cpp">#include <iostream>
- include <cstdlib>
using namespace std; //int size is a non-type agument template <class T, int size> class MyType {
T a[size];
public:
MyType() { for(int i=0; i<size; i++) a[i] = i; } T &operator[](int i){ if(i<0 || i> size-1) { cout << "\nIndex value of "; cout << i << " is out-of-bounds.\n"; exit(1); } return a[i]; }
};
int main() {
MyType<int, 10> intob; MyType<double, 15> doubleob; cout << "Integer array: "; for(int i=0; i<10; i++) intob[i] = i; for(int i=0; i<10; i++) cout << intob[i] << " "; cout << "\n"; cout << "Double array: "; for(int i=0; i<15; i++) doubleob[i] = (double) i/3; for(int i=0; i<15; i++) cout << doubleob[i] << " "; cout << "\n"; intob[12] = 100; // generates runtime error return 0;
}</source>
Integer array: 0 1 2 3 4 5 6 7 8 9 Double array: 0 0.333333 0.666667 1 1.33333 1.66667 2 2.33333 2.66667 3 3.33333 3.66667 4 4.33333 4.66667 Index value of 12 is out-of-bounds.
Loop with generic parameter
<source lang="cpp">/* The following code example is taken from the book
* "C++ Templates - The Complete Guide" * by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002 * * (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. */
- include <iostream>
template <typename T> inline T dot_product (int dim, T* a, T* b) {
T result = T(); for (int i=0; i<dim; ++i) { result += a[i]*b[i]; } return result;
} int main() {
int a[3] = { 1, 2, 3}; int b[3] = { 5, 6, 7}; std::cout << "dot_product(3,a,b) = " << dot_product(3,a,b) << "\n"; std::cout << "dot_product(3,a,a) = " << dot_product(3,a,a) << "\n";
}</source>
dot_product(3,a,b) = 38 dot_product(3,a,a) = 14
Nested template type
<source lang="cpp">/* The following code example is taken from the book
* "C++ Templates - The Complete Guide" * by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002 * * (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. */
- include <iostream>
- include <string>
- include <cstdlib>
- include <vector>
- include <deque>
- include <stdexcept>
- include <memory>
template <typename T,
template <typename ELEM, typename = std::allocator<ELEM> > class CONT = std::deque>
class Stack {
private: CONT<T> elems; // elements public: void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty(); } // assign stack of elements of type T2 template<typename T2, template<typename ELEM2, typename = std::allocator<ELEM2> >class CONT2> Stack<T,CONT>& operator= (Stack<T2,CONT2> const&);
}; template <typename T, template <typename,typename> class CONT> void Stack<T,CONT>::push (T const& elem) {
elems.push_back(elem); // append copy of passed elem
} template<typename T, template <typename,typename> class CONT> void Stack<T,CONT>::pop () {
if (elems.empty()) { throw std::out_of_range("Stack<>::pop(): empty stack"); } elems.pop_back(); // remove last element
} template <typename T, template <typename,typename> class CONT> T Stack<T,CONT>::top () const {
if (elems.empty()) { throw std::out_of_range("Stack<>::top(): empty stack"); } return elems.back(); // return copy of last element
} template <typename T, template <typename,typename> class CONT>
template <typename T2, template <typename,typename> class CONT2>
Stack<T,CONT>& Stack<T,CONT>::operator= (Stack<T2,CONT2> const& op2) {
if ((void*)this == (void*)&op2) { // assignment to itself? return *this; } Stack<T2,CONT2> tmp(op2); // create a copy of the assigned stack elems.clear(); // remove existing elements while (!tmp.empty()) { // copy all elements elems.push_front(tmp.top()); tmp.pop(); } return *this;
}
int main() {
try { Stack<int> intStack; // stack of ints Stack<float> floatStack; // stack of floats // manipulate int stack intStack.push(42); intStack.push(7); // manipulate float stack floatStack.push(7.7); // assign stacks of different type floatStack = intStack; // print float stack std::cout << floatStack.top() << std::endl; floatStack.pop(); std::cout << floatStack.top() << std::endl; floatStack.pop(); std::cout << floatStack.top() << std::endl; floatStack.pop(); } catch (std::exception const& ex) { std::cerr << "Exception: " << ex.what() << std::endl; } // stack for ints using a vector as an internal container Stack<int,std::vector> vStack; //... vStack.push(42); vStack.push(7); std::cout << vStack.top() << std::endl; vStack.pop();
}</source>
7 42 Exception: Stack<>::top(): empty stack 7
primary template to compute sqrt(N) via iteration and partial specialization to end the iteration
<source lang="cpp">/* The following code example is taken from the book
* "C++ Templates - The Complete Guide" * by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002 * * (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. */
- include <iostream>
// primary template to compute sqrt(N) via iteration template <int N, int I=1> class Sqrt {
public: enum { result = (I*I<N) ? Sqrt<N,I+1>::result : I };
}; // partial specialization to end the iteration template<int N> class Sqrt<N,N> {
public: enum { result = N };
};
int main() {
std::cout << "Sqrt<16>::result = " << Sqrt<16>::result << std::endl; std::cout << "Sqrt<25>::result = " << Sqrt<25>::result << std::endl; std::cout << "Sqrt<42>::result = " << Sqrt<42>::result << std::endl; std::cout << "Sqrt<1>::result = " << Sqrt<1>::result << std::endl;
}</source>
Sqrt<16>::result = 4 Sqrt<25>::result = 5 Sqrt<42>::result = 7 Sqrt<1>::result = 1
primary template: yield second or third argument depending on first argument
<source lang="cpp">/* The following code example is taken from the book
* "C++ Templates - The Complete Guide" * by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002 * * (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. */
- include <iostream>
// primary template: yield second or third argument depending on first argument template<bool C, typename Ta, typename Tb> class IfThenElse; // partial specialization: true yields second argument template<typename Ta, typename Tb> class IfThenElse<true, Ta, Tb> {
public: typedef Ta ResultT;
}; // partial specialization: false yields third argument template<typename Ta, typename Tb> class IfThenElse<false, Ta, Tb> {
public: typedef Tb ResultT;
};
// primary template for main recursive step template<int N, int LO=1, int HI=N> class Sqrt {
public: // compute the midpoint, rounded up enum { mid = (LO+HI+1)/2 }; // search a not too large value in a halved interval typedef typename IfThenElse<(N<mid*mid), Sqrt<N,LO,mid-1>, Sqrt<N,mid,HI> >::ResultT SubT; enum { result = SubT::result };
}; // partial specialization for end of recursion criterion template<int N, int S> class Sqrt<N, S, S> {
public: enum { result = S };
};
int main() {
std::cout << "Sqrt<16>::result = " << Sqrt<16>::result << "\n"; std::cout << "Sqrt<25>::result = " << Sqrt<25>::result << "\n"; std::cout << "Sqrt<42>::result = " << Sqrt<42>::result << "\n"; std::cout << "Sqrt<1>::result = " << Sqrt<1>::result << "\n";
}</source>
Sqrt<16>::result = 4 Sqrt<25>::result = 5 Sqrt<42>::result = 6 Sqrt<1>::result = 1
Sqrt: primary template: yield second or third argument depending on first argument
<source lang="cpp">/* The following code example is taken from the book
* "C++ Templates - The Complete Guide" * by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002 * * (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. */
- include <iostream>
// primary template: yield second or third argument depending on first argument template<bool C, typename Ta, typename Tb> class IfThenElse; // partial specialization: true yields second argument template<typename Ta, typename Tb> class IfThenElse<true, Ta, Tb> {
public: typedef Ta ResultT;
}; // partial specialization: false yields third argument template<typename Ta, typename Tb> class IfThenElse<false, Ta, Tb> {
public: typedef Tb ResultT;
};
// template to yield template argument as result template<int N> class Value {
public: enum { result = N };
}; // template to compute sqrt(N) via iteration template <int N, int I=1> class Sqrt {
public: // instantiate next step or result type as branch typedef typename IfThenElse<(I*I<N), Sqrt<N,I+1>, Value >::ResultT SubT; // use the result of branch type enum { result = SubT::result };
}; int main() {
std::cout << "Sqrt<16>::result = " << Sqrt<16>::result << std::endl; std::cout << "Sqrt<25>::result = " << Sqrt<25>::result << std::endl; std::cout << "Sqrt<42>::result = " << Sqrt<42>::result << std::endl; std::cout << "Sqrt<1>::result = " << Sqrt<1>::result << std::endl;
}</source>
Sqrt<16>::result = 4 Sqrt<25>::result = 5 Sqrt<42>::result = 7 Sqrt<1>::result = 1
template function for generic parameter and pointer to generic parameter
<source lang="cpp">/* The following code example is taken from the book
* "C++ Templates - The Complete Guide" * by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002 * * (C) Copyright David Vandevoorde and Nicolai M. Josuttis 2002. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. */
- include <iostream>
template<typename T> int f(T) {
return 1;
} template<typename T> int f(T*) {
return 2;
}
int main() {
std::cout << f<int*>((int*)0) << std::endl; std::cout << f<int>((int*)0) << std::endl;
}</source>
1 2
Use template parameter as constructor parameter
<source lang="cpp">#include <iostream.h>
- include <math.h>
template <class T> class Rect {
T x1,x2,y1,y2;
public:
Rect(T a,T b,T c,T d) { x1=a; y1=b; x2=c; y2=d; } T Area(); T Distance();
}; template <class T> T Rect<T>::Area() { return (x1-x2)*(y1-y2);} template <class T> T Rect<T>::Distance(){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
} main() {
Rect<int> p1(2.5,3.5,5.5,7); cout <<p1.Area()<<endl; cout <<p1.Distance()<<endl; Rect <float> p2(2.5,3.5,5.5,7.0); cout <<p2.Area()<<endl; cout <<p2.Distance()<<endl; return 0;
}</source>
12 5 10.5 4.60977