日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

模板:什么是Traits

發(fā)布時(shí)間:2024/6/21 综合教程 28 生活家
生活随笔 收集整理的這篇文章主要介紹了 模板:什么是Traits 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Traits不是一種語法特性,而是一種模板編程技巧。Traits在C++標(biāo)準(zhǔn)庫,尤其是STL中,有著不可替代的作用。

如何在編譯期間區(qū)分類型

下面我們看一個(gè)實(shí)例,有四個(gè)類,F(xiàn)arm、Worker、Teacher和Doctor,我們需要區(qū)分他們是腦力勞動(dòng)者還是體力勞動(dòng)者。以便于做出不同的行動(dòng)。

這里的問題在于,我們需要為兩種類型提供一個(gè)統(tǒng)一的接口,但是對(duì)于不同的類型,必須做出不同的實(shí)現(xiàn)

我們不希望寫兩個(gè)函數(shù),然后讓用戶去區(qū)分。

于是我們借助了函數(shù)重載,在每個(gè)類的內(nèi)部內(nèi)置一個(gè)work_type,然后根據(jù)每個(gè)類的word_type,借助強(qiáng)大的函數(shù)重載機(jī)制,實(shí)現(xiàn)了編譯期的類型區(qū)分,也就是編譯期多態(tài)。

代碼如下:

#include <iostream>
using namespace std;

//兩個(gè)標(biāo)簽類
struct brain_worker {}; //腦力勞動(dòng)
struct physical_worker {}; //體力勞動(dòng)

class Worker
{
public:
    typedef physical_worker worker_type;
};

class Farmer
{
public:
    typedef physical_worker worker_type;
};

class Teacher
{
public:
    typedef brain_worker worker_type;
};

class Doctor
{
public:
    typedef brain_worker worker_type;
};

template <typename T>
void __distinction(const T &t, brain_worker)
{
    cout << "腦力勞動(dòng)者" << endl;
}

template <typename T>
void __distinction(const T &t, physical_worker)
{
    cout << "體力勞動(dòng)者" << endl;
}

template <typename T>
void distinction(const T &t)
{
    typename T::worker_type _type; //為了實(shí)現(xiàn)重載
    __distinction(t, _type);
}

int main(int argc, char const *argv[])
{
    Worker w;
    distinction(w);
    Farmer f;
    distinction(f);
    Teacher t;
    distinction(t);
    Doctor d;
    distinction(d);
    return 0;
}

在distinction函數(shù)中,我們先從類型中提取出worker_type,然后根據(jù)它的類型,選取不同的實(shí)現(xiàn)。

問題來了,如果不在類中內(nèi)置worker_type,或者有的類已經(jīng)寫好了,無法更改了,那么怎么辦?

使用Traits

我們的解決方案是,借助一種叫做traits的技巧。

我們寫一個(gè)模板類,但是不提供任何實(shí)現(xiàn):

//類型traits 
template <typename T>
class TypeTraits;

然后我們為每個(gè)類型提供一個(gè)模板特化

//為每個(gè)類型提供一個(gè)特化版本
template <>
class TypeTraits<Worker>
{
public:
    typedef physical_worker worker_type;
};

template <>
class TypeTraits<Farmer>
{
public:
    typedef physical_worker worker_type;
};

template <>
class TypeTraits<Teacher>
{
public:
    typedef brain_worker worker_type;
};

template <>
class TypeTraits<Doctor>
{
public:
    typedef brain_worker worker_type;
};

然后在distinction函數(shù)中,不再是直接尋找內(nèi)置類型,而是通過traits抽取出來

template <typename T>
void distinction(const T &t)
{
    //typename T::worker_type _type;
    typename TypeTraits<T>::worker_type _type;
    __distinction(t, _type);
}

上面兩種方式的本質(zhì)區(qū)別在于,第一種是在class的內(nèi)部內(nèi)置type,第二種則是在類的外部,使用模板特化,class本身對(duì)于type并不知情。

兩種方式結(jié)合

上面我們實(shí)現(xiàn)了目的,類中沒有work_type時(shí),也可以正常運(yùn)行,但是模板特化相對(duì)于內(nèi)置類型,還是麻煩了一些。

于是,我們?nèi)匀皇褂脙?nèi)置類型,也仍然使用traits抽取work_type,方法就是為TypeTraits提供一個(gè)默認(rèn)實(shí)現(xiàn),默認(rèn)去使用內(nèi)置類型,把二者結(jié)合起來。

這樣我們?nèi)ナ褂肨ypeTraits<T>::worker_type時(shí),有內(nèi)置類型的就使用默認(rèn)實(shí)現(xiàn),無內(nèi)置類型的就需要提供特化版本

class Worker
{
public:
    typedef physical_worker worker_type;
};

class Farmer
{
public:
    typedef physical_worker worker_type;
};

class Teacher
{
public:
    typedef brain_worker worker_type;
};

class Doctor
{
public:
    typedef brain_worker worker_type;
};


//類型traits 
template <typename T>
class TypeTraits
{
public:
    typedef typename T::worker_type worker_type;
};

OK,我們現(xiàn)在想添加一個(gè)新的class,于是我們有兩種選擇,

一是在class的內(nèi)部內(nèi)置work_type,通過traits的默認(rèn)實(shí)現(xiàn)去抽取type。

一種是不內(nèi)置work_type,而是通過模板的特化,提供work_type。

例如:

class Staff
{
};

template <>
class TypeTraits<Staff>
{
public:
    typedef brain_worker worker_type;
};

測試仍然正常:

Staff s;
distinction(s);

進(jìn)一步簡化

這里我們考慮的是內(nèi)置的情形。對(duì)于那些要內(nèi)置type的類,如果type個(gè)數(shù)過多,程序編寫就容易出現(xiàn)問題,我們考慮使用繼承,先定義一個(gè)base類:

template <typename T>
struct type_base
{
    typedef T worker_type;
};

所有的類型,通過public繼承這個(gè)類即可

class Worker : public type_base<physical_worker>
{
};

class Farmer : public type_base<physical_worker>
{
};

class Teacher : public type_base<brain_worker>
{
};

class Doctor : public type_base<brain_worker>
{
};

看到這里,我們應(yīng)該明白,traits相對(duì)于簡單內(nèi)置類型的做法,強(qiáng)大之處在于:如果一個(gè)類型無法內(nèi)置type,那么就可以借助函數(shù)特化,從而借助于traits。而內(nèi)置類型僅僅使用于class類型。

以STL中的迭代器為例,很多情況下我們需要辨別迭代器的類型,

例如distance函數(shù)計(jì)算兩個(gè)迭代器的距離,有的迭代器具有隨機(jī)訪問能力,如vector,有的則不能,如list,我們計(jì)算兩個(gè)迭代器的距離,就需要先判斷迭代器能否相減,因?yàn)橹挥芯邆潆S機(jī)訪問能力的迭代器才具有這個(gè)能力。

我們可以使用內(nèi)置類型來解決。

可是,許多迭代器是使用指針實(shí)現(xiàn)的,指針不是class,無法內(nèi)置類型,于是,STL采用了traits來辨別迭代器的類型。

最后,我們應(yīng)該認(rèn)識(shí)到,traits的基石是模板特化

下篇文章,我們使用traits,來辨別一個(gè)類型是否是pod類型。

總結(jié)

以上是生活随笔為你收集整理的模板:什么是Traits的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。