從例子看C++模版

做爲現代C++中最具表現力,被應用最普遍的一個語法功能,Templates(模版),無疑應該被仔細研究。自從有了STL,模版漸漸成爲現代C++開發的主角。前不久由於老師的做業要求,我稍微學習了一下C++的模版,寫一篇入門文,請大神輕噴,謝謝。ios


首先應該看的是函數模版:這是最簡單的模版了。而函數模版中最簡單的例子,應該就是max函數了。如下是我寫的一個example:編程

#include <iostream>
    #include <string>
    using namespace std;
    //模版的聲明語法
    //這裏聲明瞭一個tmax模版,其中可能發生變化的只是一個類型T,至於T是什麼咱們並不關心
    template <typename T>
    T tmax (T a, T b)
    {
        return a < b ? b : a;
    }
    int main()
    {
        cout << tmax(3,4) << endl;
        cout << tmax(4.9,4.8) << endl;
        string s1("watch"),s2("which");
        cout << tmax(s1,s2) << endl;
        return 0;
    }

模版的魅力就在於,它不須要對象的具體類型,只須要支持進行某些方法或者運算符。這裏的tmax函數,不管拋給它的是int,double仍是string,都能正確使用,雖然實際上實現的機理是不同的。對於開發者而言,只須要知道對象支持什麼功能便可,並不須要考慮對象到底是什麼,這頗有Duck Typing的味道。須要注意的是,C++對模版的實現機理,其實是對每種可能的參數狀況分別編譯,也就是說,這段代碼實際上會產生3個tmax,分別對應int,double和string。數組

這個例子應該很好看懂。接下來咱們看類模版:安全

#include <cstdio>
#include <cstring>
#include <cstdlib>
//聲明一個模版,接收參數分別是類型名T和一個整數N
template <typename T,int N>
class Matrix
{
public:
    T d[N][N];
    T sum()
    {
        T ret=0;
        for (int i=0;i<N;++i)
        {
            for (int j=0;j<N;++j)
            {
                ret+=d[i][j];
            }
        }
        return ret;
    }
    T fill(T x)
    {
    for (int i=0;i<N;++i)
    {
        for (int j=0;j<N;++j)
            {
                d[i][j]=x;
            }
        }
    }
};
Matrix <double, 3> M;
int main()
{
    M.fill(0.1);
    M.d[1][2]+=4.5;
    printf("%lf\n",M.sum());
    return 0;
}

這個例子中,你會發現模版不必定只接收類型,也能夠接收一個變量做爲模版參數,而這些參數,能夠在聲明類的實例的時候使用。至於用法,卻簡單得讓人難以置信。類模版使用的時候須要顯式聲明模版的參數,這大概是類模版和函數模版最大的區別。由於函數模版的用途只是被調用,而類模版是用來自動構造一些類的,而構造須要必要的參數。實質的實現和函數模版同樣,類模版也是按須要編譯出一堆東西。咱們能夠看到,C++模版的本質實際上就是一個複雜而安全的宏語法,它大大擴展了C語言裏面簡陋的#define,成爲一個安全而高效的工具。閉包

如今咱們來看第三個例子,也是C++當中最讓人歎爲觀止的例子,這個例子給咱們展現了利用模版進行必定程度的函數式編程的方法。編程語言

#include <iostream>
using namespace std;

//這裏構造了一個函數對象類Plusa
template <typename T>
class Plusa
    {
    private:
        T a;
public:
    Plusa(T d)
    {
        this->a=d;
    }
    void operator() (T& x)
    {
        x+=a;
    }
};  
/* perform (l, r ,a[], f)
* 對數組a的l到r施用函數對象f
*/
template <typename T, typename FUNCT>
void perform (int l, int r, T a[], FUNCT f)
{
    for (int i=l;i<r;++i)
    {
        f(a[i]);
    }
}     
int main()
{
    double t[4]={ -0.2, 1.0, 1.2, 1.6 };
    //函數對象plus_half
    Plusa <double> plus_half(0.5);
    perform(0,3,t,plus_half);
    for (int i=0;i<4;++i)
    {
        cout << t[i] <<endl;
    }
    return 0;
}

這個例子中有一個額外的語法:函數對象。若是一個對象,它的()運算符被重載,他就變成了一個函數對象,能夠看成函數來調用。若是調用它,它和函數看上去如出一轍,但事實上它是個對象,因此它能夠被輕易地傳遞,並且能夠像Javascript的閉包那樣祕密地儲藏一些信息。函數式編程

有了函數對象,咱們能夠再寫一個模版,接受函數對象並使用函數對象,就像例子中的perform函數。函數指針這樣複雜的東西,在C++當中能夠輕易地被函數對象取代。基本上STL中全部的有比較功能的模版,全都接收函數對象,足見這個功能被應用的普遍程度。函數

以上只是一些簡單的例子,實際上C++的模版遠遠不止這麼點內容,徹底去深刻的研究,夠寫一本書,並且也有這樣一本書了:《C++ Templates》。最後,但願你們喜歡C++這門優美的編程語言。工具

相關文章
相關標籤/搜索