C++ Tutorial/template/template parameter

Материал из C\C++ эксперт
Перейти к: навигация, поиск

Default template arguments

<source lang="cpp">#include <iostream>

  1. 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>

  1. 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.
*/
  1. 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.
*/
  1. include <iostream>
  2. include <string>
  3. include <cstdlib>
  4. include <vector>
  1. include <deque>
  2. include <stdexcept>
  3. 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.
*/
  1. 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.
*/
  1. 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.
*/
  1. 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.
*/
  1. 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>

  1. 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