天天看點

C++泛型程式設計:template模闆

泛型程式設計就是以獨立于任何特定類型的方式編寫代碼,而模闆是C++泛型程式設計的基礎.

所謂template,是針對“一個或多個尚未明确的類型”所編寫的函數或類.

使用template時,可以顯示的或隐示的将類型當作參數來傳遞.

下面是一個典型的例子,傳回兩數中的較大者:

template<class T>
inline const T& MAX(const T& a,const T& b)
{
   return a>b?a:b;
}
           

在這裡,第一行将T定義為任意資料類型,于函數被調用時由調用者指定.

這個類型有關鍵字class引導,也可用typename引導,typename其實比class更直覺.

(需要注意的是,如果用到了嵌套依賴類型,則必須要用到typename).

了解:

  第一行template告訴編譯器:我在這兒定義了一個可變類型T,調用者使用什麼類型你就怎麼編譯吧!

預設模闆參數

template class可以有預設參數,例如一下聲明,允許你使用一個或多個template來聲明MyClass對象:

template<class T,class container=vector<T> >
class MyClass
{
public:
     MyClass(){}
     ~MyClass(){}
protected:
private:
};
           

如果隻傳遞一個參數,那麼預設參數可作為第二參數使用:

MyClass<int> x1; // equivalent to:
MyClass<int,vector<int> > x2;
           

注意:template預設參數根據前一個(或前一些)參數而定義。這也就意味着如果參數傳遞清單中某個參數是預設參數,那麼後面的所有參數都應該是預設參數.

關鍵字typename

關鍵字typename被用來做為類型之前的辨別符号。考慮下面例子:

template<class SubType>
struct BaseType
{
     SubType a;
};

template <class T>
class MyClass1
{
     typename T::SubType *ptr;
     // ...
};
           

這裡,typename指出SubType是class T中定義的一個類型,是以ptr是一個指向T::SubType的指針.

如果沒有typename,SubType将會被當成一個static成員,于是:

T::SubType * ptr;
           

會被解釋為類型T中的兩個子成員SubType和ptr的乘積.

成員模闆

class成員函數可以是個template,但是這樣的成員template類型既不能是virtual,也不能有預設參數,例如:

class MyClass
{
     //...
     template<class T>
     void f(T);
};
           

在這裡,MyClass::f聲明了一個成員函數,适用于任何類型參數.

這個特性常用來為template class中的成員提供自動類型轉換,例如下面的例子中,assign()的參數x,其類型必須和調用端所提供的對象的類型完全吻合:

template<class T>
class MyClass
{
public:
     MyClass();
     ~MyClass();
     void assign(const MyClass<T>& x) // x must have same type as *this
     {
           value=x.value;
     }
     // ...
protected:
private:
     T value;
};
           

如果使用了兩個類型,即使兩個類型之間可以自動轉換,也會出錯:

void fun()
{
     MyClass<double> d;
     MyClass<int> i;

     d.assign(d); // OK
     d.assign(i); // ERROR: i is MyClass<int> but MyClass<double> is required
}
           

  對于一個template class中的template成員,遵循“先入為主”,如果第一次指定了類型,那麼後面都要和第一次保持一緻.

但如果要指定兩個不同類型的類成員變量怎麼辦呢?

方法很簡單,我們将成員變量在使用一個和class不同的template類型就行:

template<class T>
class MyClass
{
public:
     MyClass();
     ~MyClass();
     template<class X> // member template
     void assign(const MyClass<X>& x) // allow different template types
     {
           value = x.getValu();
     }
     T getValue() const
     {
           return value;
     }
     // ...
protected:
private:
     T value;
};

void fun()
{
     MyClass<double> d;
     MyClass<int> i;
     
     d.assign(d); // OK
     i.assign(i); // OK (int is assigned to double)
}
           

      |  Github |  Facebook  |  Twitter |

繼續閱讀