C++ Tutorial/template/template parameter

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

Default template arguments

#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;
}
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

/* 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);
}

Demonstrate non-type template arguments

#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;
}
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

/* 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";
}
dot_product(3,a,b) = 38
dot_product(3,a,a) = 14

Nested template type

/* 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();
}
7
42
Exception: Stack<>::top(): empty stack
7

primary template to compute sqrt(N) via iteration and partial specialization to end the iteration

/* 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;
}
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

/* 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";
}
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

/* 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<I>
                               >::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;
}
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

/* 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;
}
1
2

Use template parameter as constructor parameter

#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;
}
12
5
10.5
4.60977