2008 July 11th Friday (七月 十一日 金曜日)

   The template in C++ language is just a variant of macro.

//arraytp.h  -- Array Template
#ifndef ARRAYTP_H_
#define ARRAYTP_H_

#include <iostream>
using namespace std;
#include <cstdlib>

template <class T, int n>
class ArrayTP
{
private:
    T ar[n];
public:
    ArrayTP() {};
    explicit ArrayTP(const T & v);
    virtual T & operator[](int i);
    virtual const T & operator[](int i) const;
};

template <class T, int n>
ArrayTP<T,n>::ArrayTP(const T & v)
{
    for (int i = 0; i < n; i++)
        ar[i] = v;
}

template <class T, int n>
T & ArrayTP<T,n>::operator[](int i)
{
    if (i < 0 || i >= n)
    {
        cerr << "Error in array limits: " << i
            << " is out of range/n";
        exit(1);
    }
    return ar[i];
}

template <class T, int n>
const T & ArrayTP<T,n>::operator[](int i) const
{
    if (i < 0 || i >= n)
    {
        cerr << "Error in array limits: " << i
            << " is out of range/n";
        exit(1);
    }
    return ar[i];
}

#endif

  The parameter "n" has some restrictions.  It can be an integral type, an enumeration type, a reference,
or a pointer.  Thus, double m is ruled out, but double &rm and double *pm are allowed. Also, the template
code can't alter the value of the argument or take its address.  Thus, in the ArrayTP template, expressions
such as n++ or &n would not be allowed. Also, when you instantiate a template, the value used for the expression
argument should be a constant expression.

Template Specializations

  Implicit Instantiations

ArrayTb<int, 100> stuff; // implicit instantiation

  The compiler doesn't generate an implicit instantiation of the class until it needs an object:

ArrayTb<double, 30> * pt;     // a pointer, no object needed yet
pt = new ArrayTb<double, 30>; // now an object is needed

  Explicit Instantiations

  The compiler generates an explicit instantiation of a class declaration when you declare a class using the
keyword template and indicating the desired type or types. The declaration should be in the same namespace as
the template definition. For example, the declaration

template class ArrayTb<String, 100>; // generate ArrayTB<String, 100> class

  In this case the compiler generates the class definition, including method definitions, even though no object
of the class has yet been created or mentioned. Just as with the implicit instantiation, the general template is
used as a guide to generate the specialization.

  Explicit Specializations

  A specialized class template definition has the following form:

template <> class Classname<specialized-type-name> { ... };

template <> class SortedArray<char *>
{
     ...// details omitted
};

SortedArray<int> scores;    // use general definition
SortedArray<char *> dates;  // use specialized definition

  Partial Specializations

// general template
    template <class T1, class T2> class Pair {...};
// specialization with T2 set to int
    template <class T1> class Pair<T1, int> {...};
// specialization with T1 and T2 set to int
    template <> class Pair<int, int> {...};

Pair<double, double> p1; // use general Pair template
Pair<double, int> p2;    // use Pair<T1, int> partial specialization
Pair<int, int> p3;       // use Pair<int, int> explicit specialization

// general template
    template <class T1, class T2, class T3> class Trio{...};
// specialization with T3 set to T2
    template <class T1, class T2> class Trio<T1, T2, T2> {...};
// specialization with T3 and T2 set to T1*
    template <class T1> class Trio<T1, T1*, T1*> {...};

Trio<int, short, char *> t1; // use general template
Trio<int, short> t2; // use Trio<T1, T2, T2>
Trio<char, char *, char *> t3; use Trio<T1, T1*, T1*>

  Member Templates

// tempmemb.cpp -- template members
#include <iostream>
using namespace std;

template <typename T>
class beta
{
private:
    template <typename V>  // nested template class member
    class hold
    {
    private:
        V val;
    public:
        hold(V v  = 0) : val(v) {}
        void show() const { cout << val << endl; }
        V Value() const { return val; }
    };
    hold<T> q;           // template object
    hold<int> n;         // template object
public:
    beta( T t, int i) : q(t), n(i) {}
    template<typename U>   // template method
    U blab(U u, T t) { return (n.Value() + q.Value()) * u / t; }
    void Show() const {q.show(); n.show();}
};
int main()
{
    beta<double> guy(3.5, 3);

    guy.Show();
    cout << guy.blab(10, 2.3) << endl;
    cout << "Done/n";
    return 0;
}

  Or another way define a memeber template.

template <typename T>
class beta
{
private:
    template <typename V>  // declaration
    class hold;
    hold<T> q;
    hold<int> n;
public:
    beta( T t, int i) : q(t), n(i) {}
    template<typename U>   // declaration
    U blab(U u, T t);
    void Show() const {q.show(); n.show();}
};
// member definition
template <typename T>
  template<typename V>
    class beta<T>::hold
    {
    private:
        V val;
    public:
        hold(V v  = 0) : val(v) {}
        void show() const { cout << val << endl; }
        V Value() const { return val; }
    };

// member definition
template <typename T>
  template <typename U>
    U beta<T>::blab(U u, T t)
    {
       return (n.Value() + q.Value()) * u / t;
    }

  The definitions have to identify T, V, and U as template parameters. Because the templates are nested, you have
to use the

template <typename T>
  template <typename V>

syntax instead of the

template<typename T, typename V>

syntax.

  Templates As Parameters

// tempparm.cpp -- template template parameters
#include <iostream>
using namespace std;
#include "stacktp.h"

template <template <typename T> class Thing>
class Crab
{
private:
    Thing<int> s1;
    Thing<double> s2;
public:
    Crab() {};
    // assumes the thing class has push() and pop() members
    bool push(int a, double x) { return s1.push(a) && s2.push(x); }
    bool pop(int & a, double & x){ return s1.pop(a) && s2.pop(x); }
};

int main()
{
    Crab<Stack> nebula;
// Stack must match template <typename T> class thing
    int ni;
    double nb;

    while (cin>> ni >> nb && ni > 0 && nb > 0)
    {
        if (!nebula.push(ni, nb))
            break;
    }

    while (nebula.pop(ni, nb))
           cout << ni << ", " << nb << endl;
    cout << "Done./n";

    return 0;
}

  The Thing<int> is instantiated as Stack<int> and Thing<double> is instantiated as Stack<double>. In short,
the template parameter Thing is replaced by whatever template type is used as a template argument in declaring
a Crab object.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值