模板特化

模板是C++泛型編程編程的基礎(chǔ),STL從頭到尾都是模板泛型編程

函數(shù)模板

template<class T>
T add(T a, T b) { return a + b;}

int main()
{
    int a = 1, b = 2;
    std::cout << add(a + b) << std::endl;
    return 0;
}

類模板

template<class T>
class A
{
public:
    explicit A(T val) : t(val) { }
    T add(T x) { return t + x; }    
private:
    T t;
};

int main()
{
    A<int> a(10);
    std::cout << a.add(5) << std::endl;
    return 0;
}

幾個(gè)需要注意的點(diǎn)
1. 類模板的和函數(shù)模板都必須定義在.h頭文件中
2. 模板的實(shí)例化類型確定是在編譯期間
3. 只是模板寫(xiě)好了,編譯一般不會(huì)很多出錯(cuò),出錯(cuò)一般會(huì)在實(shí)例化編譯之后
4. 模板實(shí)例化只會(huì)實(shí)例化用到的部分,沒(méi)有用到的部分將不會(huì)被實(shí)例化

模板特化

函數(shù)模板全特化

template< >                                  // 全特化 注意語(yǔ)法
double add(double a, double b)  { return a + b; }

int main()
{
    int x = 10, y = 20;
    double z = 1.1, w = 2.2;
    std::cout << add(x, y) << std::endl;   // 調(diào)用普通版本
    std::cout << add(z, w) << std::endl;   // 調(diào)用全特化版本
    return 0;
}

函數(shù)模板重載(不存在偏特化)

template<class T1>  // 重載版本,接收參數(shù)為指針
T1 add(T1* a, T1* b) { return *a + *b; }   
int main()
{
    int a = 10, b = 20;
    int *x = &a, *y = &b;
    add(a, b);    // 調(diào)用普通模板
    add(x, y);   // 調(diào)用重載的模板
    return 0;
}

類模板的偏特化

  • 形式一
template<class T1, class T2>      // 普通版本,有兩個(gè)模板參數(shù)
class B { ..... };

template<class T2>            // 偏特化版本,指定其中一個(gè)參數(shù),即指定了部分類型
class B<int , T2> { ..... };  // 當(dāng)實(shí)例化時(shí)的第一個(gè)參數(shù)為int 則會(huì)優(yōu)先調(diào)用這個(gè)版本
  • 形式二
template<class T>     // 普通版本
class B { ..... };

template<class T>   //這個(gè)偏特化版本只接收指針類型的模板實(shí)參 
class B<T*> { ..... }; 

template<class T>
class B<T&> { ..... };     // 這個(gè)偏特化版本只接受引用類型的模板實(shí)參
  • 形式三
template<class T>    //普通版本
class B { ..... };

template<class T>   // 這種只接受用T實(shí)例化的vector的模板實(shí)參.也是一種偏特化
class B<vector<T>> { ......  };  

幾個(gè)值得注意的地方
1. 特例化本質(zhì)上是我們頂替了編譯器的工作,我們幫編譯器做了類型推導(dǎo)
2. 全特化本質(zhì)上是一個(gè)實(shí)例,而偏特化本質(zhì)上還是一個(gè)模板,只是原來(lái)模板的一個(gè)子集
3. 所以全特化的函數(shù)模板,本質(zhì)上是實(shí)例,從而不會(huì)與函數(shù)模板產(chǎn)生二義性
4. 若想讓用戶能使用特例化版本,特例化版本必須與模板定義在同一個(gè).h頭文件中

偏特化在STL中最重要的兩個(gè)應(yīng)用

1. 應(yīng)用在迭代器設(shè)計(jì)中,為了使迭代器既可以萃取出值類型,又可以包容原生指針
如果要通過(guò)一個(gè)迭代器就能知道它的值類型,那么一般會(huì)使用iterator_traits
迭代器萃取技術(shù)的兩個(gè)核心是:
a. 在每個(gè)迭代器類中定義value_type值類型的類型成員,這樣直接通過(guò)迭代器的value_type類型成員就可以知道值類型
b. 問(wèn)題就在于,迭代器必須兼容原生指針,而原生指針很難被重新定義,即要在原生指針的類中添加value_type的值類型的類型成員.這時(shí)候,靠的就是類模板的偏特化了.新添加一層iterator_traits類,專門(mén)萃取迭代器的屬性,然后再對(duì)iterator_traits類設(shè)計(jì)原生指針與原生引用的偏特化版本,就解決了這個(gè)棘手的問(wèn)題

2.type_traits類型萃取,對(duì)待特殊類型,特殊處理,提高效率
對(duì)于沒(méi)有構(gòu)造函數(shù),析構(gòu)函數(shù)等的內(nèi)置類型,如果與復(fù)雜類型一樣,執(zhí)行同樣的操作,顯然是效率不高的先實(shí)現(xiàn)一個(gè)對(duì)所有類型都設(shè)置一個(gè)最保守值的type_traits模板類,然后再對(duì)每個(gè)內(nèi)置類型設(shè)置偏特化版本,內(nèi)置類型設(shè)置一個(gè)更為激進(jìn)的值,表明可以采取更為高效的操作來(lái)提高效率比如copy函數(shù),如果傳遞的對(duì)象是一個(gè)復(fù)雜類型,那么可能只能采取最保守的處理方式,一個(gè)一個(gè)的構(gòu)造;如果是內(nèi)置類型,這樣顯然太低效,使用memcpy()可能會(huì)好一些

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容