C++11 模板元編程 - Traits in TLP


C++標(biāo)準(zhǔn)庫(kù)STL中的type_traits文件中喊式,已經(jīng)有了比較全面的C++ trait組件亮曹,可以用來(lái)對(duì)代碼做各種靜態(tài)反射。

TLP庫(kù)中補(bǔ)充了如下幾個(gè)有用的trait工具宅此,這些trait在后面介紹的TLP的sample代碼中會(huì)用到秦踪。

  • __is_convertible(T, U):用于判斷類型T是否可以默認(rèn)轉(zhuǎn)型為U類型褐捻;

  • __is_both_convertible(T, U):用于判斷類型T和U之間是否可以互相轉(zhuǎn)型;

  • __is_base_of(T, U):用于判斷類型T是否是類型U的父類椅邓;

  • __is_built_in(T):用于判斷類型T是否為C++內(nèi)置類型柠逞;

  • __lambda_return(Lambda):針對(duì)一個(gè)Lambda表達(dá)式類型,計(jì)算其返回值類型景馁;

  • __lambda_paras(Lambda):針對(duì)一個(gè)Lambda表達(dá)式類型板壮,計(jì)算其參數(shù)類型;將所有參數(shù)類型放在一個(gè)TypeList中返回合住;

  • __lambda_para(Lambda绰精,Index):針對(duì)一個(gè)Lambda表達(dá)式類型撒璧,返回其Index位置的參數(shù)的類型。如果沒(méi)有參數(shù)返回NullType笨使;

這些trait工具的實(shí)現(xiàn)大多在前面都已經(jīng)介紹過(guò)卿樱,除過(guò)最后三個(gè)關(guān)于lambda的。

C++11引入了lambda特性硫椰,這是一個(gè)非常有用的特性繁调,尤其對(duì)于編寫(xiě)框架。現(xiàn)實(shí)中我們經(jīng)常把變化的算法交給客戶自定義最爬,然后通過(guò)語(yǔ)言提供的技術(shù)手段再注入給框架涉馁。相比傳統(tǒng)使用虛接口做注入门岔,支持lambda會(huì)讓客戶的代碼更加簡(jiǎn)潔和緊湊爱致。在框架中,我們可能會(huì)要提取用戶注入的lambda表達(dá)式的返回值類型或者參數(shù)類型寒随。TLP中的__lambda_return()糠悯、__lambda_paras()__lambda_para()就是幫助代碼完成這些事情的。它們的實(shí)現(xiàn)如下:

// "tlp/traits/LambdaTraits.h"

template<typename T>
struct LambdaTraits
: LambdaTraits<decltype(&T::operator())>
{
};

template<typename C, typename R, typename ... Args>
struct LambdaTraits<R (C::*)(Args...) const>
{
    using ReturnType = R;
    using ParaTypes = typename TypeList<Args...>::Result;
};

#define __lambda_return(...)  typename LambdaTraits<__VA_ARGS__>::ReturnType

#define __lambda_paras(...)   typename  LambdaTraits<__VA_ARGS__>::ParaTypes

#define __lambda_para(lambda, index) __at(__lambda_paras(lambda), __int(index))

如上妻往,我們主要靠模板特化的模式匹配特性來(lái)萃取出我們想要的類型信息的:template<typename C, typename R, typename ... Args> struct LambdaTraits<R (C::*)(Args...) const>互艾。我們把返回值類型保存在ReturnType,而把所有的參數(shù)類型保存在一個(gè)TypeList中:using ParaTypes = typename TypeList<Args...>::Result讯泣。

可以如下測(cè)試這些lambda traits:

TEST("calculate the return type and parameter types of a lambda")
{
    template<typename T>
    void testLambdaTraits(const T&)
    {
        ASSERT_EQ(__lambda_return(T), int);
        ASSERT_EQ(__lambda_paras(T), __type_list(const int*, char));
        ASSERT_EQ(__lambda_para(T, 0), const int*);
        ASSERT_EQ(__lambda_para(T, 1), char);
        ASSERT_EQ(__lambda_para(T, 2), __null());
    }

    void run()
    {
        testLambdaTraits([](const int* x, char y){ return *x + y; });
    }
}纫普;

上面我們對(duì)lambda表達(dá)式[](const int* x, char y){ return *x + y; }進(jìn)行了萃取,判斷其返回類型是int好渠,參數(shù)類型分別是const int *char昨稼。

上面的測(cè)試中,之所以要定義testLambdaTraits函數(shù)拳锚,主要是為了從lambda表達(dá)式對(duì)象中提取出它的類型假栓,然后再傳給__lambda_return()等。這種通過(guò)函數(shù)模板來(lái)對(duì)具體對(duì)象或變量進(jìn)行推導(dǎo)以獲取其類型的手段霍掺,在C++11之前是一種常用技巧匾荆。由于C++11引入了decltype關(guān)鍵字,所以以后都不用再這么繞了杆烁!我們重新實(shí)現(xiàn)測(cè)試用例如下:

TEST("calculate the return type and parameter types of a lambda")
{
    void run()
    {
        auto f = [](const int* x, char y){ return *x + y; };
        using Lambda = decltype(f);

        ASSERT_EQ(__lambda_return(Lambda), int);
        ASSERT_EQ(__lambda_paras(Lambda), __type_list(const int*, char));
        ASSERT_EQ(__lambda_para(Lambda, 0), const int*);
        ASSERT_EQ(__lambda_para(Lambda, 1), char);
        ASSERT_EQ(__lambda_para(Lambda, 2), __null());
    }
};

之所以還需要run()方法,是因?yàn)門EST本質(zhì)上是一個(gè)類兔魂,而auto f不能是定義為類的成員的入热,但是可以定義到函數(shù)里面晓铆。

關(guān)于TLP中的trait就介紹到這里绰播,更多的關(guān)于trait的應(yīng)用在后面的還會(huì)專門介紹蠢箩。


Test in TLP

返回 C++11模板元編程 - 目錄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谬泌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子陪蜻,更是在濱河造成了極大的恐慌贱鼻,老刑警劉巖邻悬,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件父丰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蛾扇,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門医寿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蘑斧,“玉大人,你說(shuō)我怎么就攤上這事沟突〔洞” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵职辅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我簇秒,道長(zhǎng)趋观,這世上最難降的妖魔是什么锋边? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任豆巨,我火速辦了婚禮搀矫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己敏弃,他們只是感情好麦到,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布绿饵。 她就那樣靜靜地躺著,像睡著了一般瓶颠。 火紅的嫁衣襯著肌膚如雪拟赊。 梳的紋絲不亂的頭發(fā)上粹淋,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天吸祟,我揣著相機(jī)與錄音桃移,去河邊找鬼屋匕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛借杰,可吹牛的內(nèi)容都是我干的过吻。 我是一名探鬼主播蔗衡,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼纤虽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼乳绕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起刷袍,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎樊展,沒(méi)想到半個(gè)月后专缠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡墩弯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年吩跋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片引矩。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡梁丘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出旺韭,到底是詐尸還是另有隱情氛谜,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布区端,位于F島的核電站值漫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏织盼。R本人自食惡果不足惜杨何,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望悔政。 院中可真熱鬧晚吞,春花似錦、人聲如沸谋国。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至捌蚊,卻和暖如春集畅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缅糟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工挺智, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人窗宦。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓赦颇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親赴涵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子媒怯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容