C++ Tutorial/template/template parameter — различия между версиями
Admin (обсуждение | вклад) м (1 версия: Импорт контента...) |
Admin (обсуждение | вклад) м (1 версия: Импорт контента...) |
(нет различий)
|
Текущая версия на 10:30, 25 мая 2010
Содержание
- 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
#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