C++?Tuple元組實(shí)現(xiàn)?Metaprogramming

# C++ Tuple元組實(shí)現(xiàn) Metaprogramming

核心玩法:模板遞歸祝峻、偏特化

? ? template<typename ... Tn>struct Tuple;

? ?

? ? template<typename T0,typename ... Tn>

? ? struct Tuple<T0,Tn...>{

? ? ? ? T0 head;

? ? ? ? Tuple<Tn...>tail;

? ? ? ? constexpr static int size = sizeof...(Tn)+1;

? ? ? ? Tuple():head(0){

? ? ? ? }

? ? ? ?

? ? ? ? Tuple(const T0 &h,const Tuple<Tn...> &t):head(h),tail(t){

? ? ? ? }

? ? ? ?

? ? ? ? Tuple(const Tuple<T0,Tn...> & a):head(a.head),tail(a.tail){

? ? ? ? }

? ? ?

? ? ? ? template<typename _T0,typename ... _Tn,typename =std::enable_if_t<sizeof...(Tn)==sizeof...(_Tn)>>

? ? ? ? Tuple( _T0&& a, _Tn && ...? n):head(std::forward<_T0>(a)),tail(std::forward<_Tn>(n)...){

? ? ? ? }

? ? };

? ?

? ? template<typename T>

? ? struct Tuple<T>{

? ? ? ? constexpr static int size = 1;

? ? ? ? T head;

? ? ? ?

? ? ? ? Tuple():head(0){

? ? ? ? }

? ? ? ? template<typename _T>

? ? ? ? Tuple( _T&& a):head(a){

? ? ? ? }

? ? };

## 1吟策、類型搜索

從Tuple中搜索某個(gè)類型,只要存在一個(gè),則返回true,否則返回false 例如:Tuple<char,short,double> 類型中是否包含 某個(gè)類型(short)扁誓?只要包含返回true,否則返回false

```

template<typename Patten,typename ...T>struct Search;

? ?

template<typename Patten,typename H,typename ...T>

struct Search<Patten,Tuple<H,T...>>: std::conditional_t<std::is_same_v<Patten, H>,std::true_type, Search<Patten, Tuple<T...>>> {

};

template<typename Patten>

struct Search<Patten,Tuple<>>: std::false_type {

};

///Test

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double> a('s',5,6.8);

? ?

? ? bool x0x = Search<short, decltype(a)>::value;/// true

? ? bool x2x = Search<double, decltype(a)>::value;/// true

? ? bool x3x = Search<unsigned short, decltype(a)>::value;/// false

? ? bool x4x = Search<int, decltype(a)>::value;/// false

?

? ? return 0;

}

```

## 2邓梅、類型搜索(并統(tǒng)計(jì)個(gè)數(shù))

或者,我們可以更近一步乾蛤,從Tuple中搜索某個(gè)類型每界,并且統(tǒng)計(jì)出有多少個(gè)該類型?

```

template<typename Patten,typename ...T>struct Count;

? ?

template<typename Patten,typename H,typename ...T>

struct Count<Patten,Tuple<H,T...>>:std::integral_constant<int, std::is_same_v<Patten, H> + Count<Patten, Tuple<T...>>::value > {

};

template<typename Patten>

struct Count<Patten,Tuple<>>: std::integral_constant<int, 0> {

};

///Test

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double,short,int,double,double> a;

? ?

? ? int c0 = Count<char, decltype(a)>::value;///1

? ? int c1 = Count<short, decltype(a)>::value;///2

? ? int c2 = Count<double, decltype(a)>::value;///3

? ? int c3 = Count<bool, decltype(a)>::value;///0

? ? int c4 = Count<unsigned char, decltype(a)>::value;///0

? ? int c5 = Count<int, decltype(a)>::value;///1

? ?

? ? return 0;

}

```

有了上述統(tǒng)計(jì)類型個(gè)數(shù)的方法家卖,判斷Tuple中是否包含某個(gè)類型還可以修改成如下:

原理:該類型個(gè)數(shù)大于0返回true,否則返回false眨层,不過效率相對(duì)低點(diǎn),因?yàn)椴还苁欠癜紩?huì)完全遍歷完整個(gè)類型列表上荡。

```

///判斷是否存在某個(gè)類型趴樱?

template<typename Patten,typename ...T>

using search_t = std::conditional_t< (Count<Patten, T...>::value > 0) , std::true_type, std::false_type>;

///Test

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double,short,double,double> a;

? ?

? ? bool x0x = search_t<short, decltype(a)>::value;/// true

? ? bool x2x = search_t<double, decltype(a)>::value;/// true

? ? bool x3x = search_t<unsigned short, decltype(a)>::value;/// false

? ? bool x4x = search_t<int, decltype(a)>::value;/// false

? ?

? ? return 0;

}

```

## 3、類型搜索(返回首次匹配到該類型時(shí)的位置)

或者,我們可以更更再近一步叁征,從Tuple中搜索某個(gè)類型纳账,并返回第一次匹配到該類型時(shí)的位置(從1開始),如果沒有匹配到返回0

```

template<typename Patten,typename ...T>struct SearchHIdx;

?

template<typename Patten,typename H,typename ...T>

struct SearchHIdx<Patten,Tuple<H,T...>>: std::integral_constant<int,(std::is_same_v<Patten, H> ? sizeof...(T) :? SearchHIdx<Patten, Tuple<T...>>::value )>{

};

template<typename Patten>

struct SearchHIdx<Patten,Tuple<>>: std::integral_constant<int, 0> {

};

template<typename Patten,typename ...T>struct SearchH;

template<typename Patten,typename ...T>

struct SearchH<Patten,Tuple<T...>> :std::integral_constant<int,((SearchHIdx<Patten, Tuple<T...>>::value == 0) ? 0 : (sizeof...(T) - SearchHIdx<Patten, Tuple<T...>>::value))>{

};

///Test

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double,short,double,double> a;///6

? ?

? ? int idx0 = SearchH<char, decltype(a)>::value;///1

? ? int idx1 = SearchH<short, decltype(a)>::value;///2

? ? int idx2 = SearchH<double, decltype(a)>::value;///3

? ? int idx3 = SearchH<int, decltype(a)>::value;///0捺疼, Not found

? ? return 0;

}

```

## 4疏虫、萃取Tuple指定位置的類型

我們可以從Tuple中萃取指定位置的類型,例如第一個(gè)啤呼、最后一個(gè)卧秘、或者第n個(gè)...

可以例如模版函數(shù)聲明,代碼如下:

```

template<typename Head,typename ...Trail>

Head ForntT(Tuple<Head,Trail...>);///獲取第一個(gè)類型

///template<typename ...Head,typename Trail>///獲取最后一個(gè)類型

///Trail BackT(Tuple<Head...,Trail>);///【無法使用該模板】:因?yàn)門uple<Head...,Trail>類型作為函數(shù)參數(shù)編譯器推斷不出來

template<typename Head,typename ...Trail>

Tuple<Trail...> PopForntT(Tuple<Head,Trail...>);///移除第一個(gè)類型

template<typename Head,typename ...Trail>

Tuple<Head,Trail...> PushForntT(Head ,Tuple<Trail...>);///插入類型到Tuple的首部

template<typename ...Head,typename Trail>

Tuple<Head...,Trail> PushBackT(Tuple<Head...>,Trail);///插入類型到Tuple的尾部

///Test

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double> a;

?

? ? decltype(ForntT(a)) x1;/// char x1;

? ? decltype(PopForntT(a)) x2;///? Tuple<short,double> x2;

? ? decltype(PushBackT(a,false)) x3;///? Tuple<char,short,double,bool> x3;

? ?

? ? return 0;

}

```

通過上述函數(shù)模板的聲明媳友,可以利用編譯器推斷出來Tuple的部分位置的情況斯议,但是上述方法無法推斷出Tuple的最后一個(gè)類型,或者移除最后一個(gè)類型醇锚,我們得想其他辦法哼御。我們嘗試用類模板偏特化試試看:

```

template<typename T>struct FrontC;

template<typename Head,typename ...Trail>

struct FrontC<Tuple<Head,Trail...>>{///獲取第一個(gè)類型

? ? using type = Head;

};

//template<typename T>struct BackC;

//

//template<typename ...Head,typename Trail>

//struct BackC<Tuple<Head...,Trail>>{///獲取最后一個(gè)類型,無法編譯通過

//? ? using type = Trail;

//};

template<typename T>struct PopFrontC;

template<typename Head,typename ...Trail>

struct PopFrontC<Tuple<Head,Trail...>>{///移除第一個(gè)類型

? ? using type = Tuple<Trail...>;

};

template<typename Head,typename ...Trail>struct PushFrontC;

template<typename Head,typename ...Trail>

struct PushFrontC<Head,Tuple<Trail...>>{///插入類型到Tuple首部

? ? using type = Tuple<Head,Trail...>;

};

template<typename Trail,typename ...Head>struct PushBackC;

template<typename Trail,typename ...Head>

struct PushBackC<Trail,Tuple<Head...>>{///插入類型到Tuple尾部

? ? using type = Tuple<Head...,Trail>;

};

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double> a;

?

? ? FrontC<decltype(a)>::type x1;/// char x1;

? ? PopFrontC<decltype(a)>::type x2;/// Tuple<short,double> x2;

? ? PushFrontC<bool, decltype(a)>::type x3;/// Tuple<bool,char,short,double> x3;

? ? PushBackC<int, decltype(a)>::type x4;/// Tuple<char,short,double,int> x4;

? ?

? ? return 0;

}

```

發(fā)現(xiàn)類模板也無法萃取出Tuple的最后一個(gè)類型焊唬,或者移除最后一個(gè)類型恋昼。因?yàn)門uple<Head...,Trail>這樣的類型,無法被偏特化赶促。

### 萃取Tuple的指定位置的類型

通過Supscript可以萃取指定位置的類型液肌,代碼如下:

```

template <int idx, typename ...T>

struct Supscript;

template <int idx,typename H, typename ...T>

struct Supscript<idx,Tuple<H,T...>>{

private:

? ? using last = typename Supscript<idx-1,Tuple<T...>>::type;

public:

? ? using type = std::conditional_t<idx==0, H,last>;

};

template <typename H,typename ...T>

struct Supscript<0,Tuple<H,T...>>{

? ? using type = H;

};

///為何不能這樣寫?

///template <typename ...T>

///using last_t = typename Supscript<sizeof...(T)-1, T...>::type;

template<typename ...T>struct LastType;

template<typename ...T>

struct LastType<Tuple<T...>>{

? ? using type = typename Supscript<sizeof...(T)-1, Tuple<T...>>::type;

};

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double,bool> a;

? ? Tuple<short,double> av;

? ? Tuple<char> ab;

? ?

? ? Supscript<0, decltype(a)>::type xx4;

? ? Supscript<1, decltype(a)>::type xx43;

? ? Supscript<2, decltype(a)>::type x4x4;

? ? Supscript<3, decltype(a)>::type xx554;

? ? Supscript<0, decltype(av)>::type xx444;

? ? Supscript<1, decltype(av)>::type xx334;

? ?

? ? LastType<decltype(a)>::type xaa2a;///bool xaa2a;

? ? LastType<decltype(av)>::type xaa3a;///double xaa3a;

? ? LastType<decltype(ab)>::type xa4aa;///char xa4aa;

? ?

? ? return 0;

}

```

上述代碼鸥滨,也可以用另外一種寫法實(shí)現(xiàn)【好像換湯不換藥嗦哆,邏輯是一樣的】,修改后如下:

```

template <int idx, typename ...T>

struct Supscript;

template <int idx,typename H, typename ...T>

struct Supscript<idx,Tuple<H,T...>>{

? ? using type = typename? Supscript<idx-1,Tuple<T...>>::type;

};

template <typename H, typename ...T>

struct Supscript<0,Tuple<H,T...>>{

? ? using type = H;

};

template <int idx, typename ...T>

using supscript_t = typename Supscript<idx,T...>::type;

///test

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double,bool> a;

? ? Tuple<short,double> av;

? ? Tuple<char> ab;

? ?

? ? supscript_t<0, decltype(a)> xxx0;/// char xxx0;

? ? supscript_t<1, decltype(a)> xxx1;/// short xxx1;

? ? supscript_t<2, decltype(a)> xxx2;/// double xxx2;

? ? supscript_t<3, decltype(a)> xxx3;///bool xxx3;

? ? supscript_t<0, decltype(av)> xxx4;///short xxx4

? ? supscript_t<1, decltype(av)> xxx5;///double xxx5;

? ? supscript_t<0, decltype(ab)> xxx6;/// char xxx6;

? ? supscript_t<1, decltype(ab)> xxx7;/// Error

? ?

? ? return 0;

}

```

經(jīng)過上述代碼改進(jìn)后婿滓,Supscript依然可以萃取到任意指定位置的類型老速。

## 5、翻轉(zhuǎn)Tuple的類型列表

借助上面PushBackC這個(gè)方法可以輕松實(shí)現(xiàn)Tuple類型反轉(zhuǎn)凸主。

```

template <int idx, typename ...T>

struct Reverse;

template <int idx,typename H, typename ...T>

struct Reverse<idx,Tuple<H,T...>>{

? ? using type =? typename PushBackC<H,typename Reverse<idx-1,Tuple<T...>>::type>::type;

};

template <typename H, typename ...T>

struct Reverse<0,Tuple<H,T...>>{

? ? using type = Tuple<H>;

};

template <int idx, typename ...T>

using reverse_t = typename Reverse<idx, T...>::type;

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double,bool> a;

? ? Tuple<short,double> av;

? ? Tuple<char> ab;

? ?

? ? reverse_t<0, decltype(a)> xfdas0;/// Tuple<char> xfdas0;

? ? reverse_t<1, decltype(a)> xfdas1;/// Tuple<short,char> xfdas1;

? ? reverse_t<2, decltype(a)> xfdas2;/// Tuple<double,short,char> xfdas2;

? ? reverse_t<3, decltype(a)> xfdas3;/// Tuple<bool,double,short,char> xfdas3;

? ? reverse_t<0, decltype(av)> xfdas4;/// Tuple<short> xfdas4;

? ? reverse_t<1, decltype(av)> xfdas5;/// Tuple<double,short> xfdas5;

? ?

? ? return 0;

}

```

## 6橘券、兩個(gè)Tuple合并

可以想辦法把兩個(gè)Tuple內(nèi)部的類型合并成到一個(gè)Tuple中:

```

template<typename T,typename ...T1> struct Merge;

template<typename T,typename T1,typename ...T2>

struct Merge<T,Tuple<T1,T2...>>{

private:

? ? using Head = decltype(PushBackT(T(),T1()));

? ? using Trail = Tuple<T2...>;

public:

? ? using type = typename Merge<Head,Trail>::type;

};

template<typename T,typename T1>

struct Merge<T,Tuple<T1>>{

public:

? ? using type = decltype(PushBackT(T(),T1()));

};

template<typename T,typename ...T1>

using merge_t = typename Merge<T, T1...>::type;

int main(int argc, const char * argv[]) {

? ? Tuple<char,short,double,bool> a;

? ? Tuple<short,double> av;

? ? Tuple<char> ab;

? ?

? ? merge_t<decltype(ab), decltype(av)> x11;///Tuple<char,short,double> x11;

? ? merge_t<decltype(av), decltype(av)> x12;/// Tuple<short,double,short,double> x12;

? ? merge_t<decltype(av), decltype(ab)> x13;/// Tuple<short,double,char> x13;

? ?

? ? return 0;

}

```

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市卿吐,隨后出現(xiàn)的幾起案子旁舰,更是在濱河造成了極大的恐慌,老刑警劉巖嗡官,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箭窜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡衍腥,警方通過查閱死者的電腦和手機(jī)绽快,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門芥丧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人坊罢,你說我怎么就攤上這事∩玫ⅲ” “怎么了活孩?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)乖仇。 經(jīng)常有香客問我憾儒,道長(zhǎng),這世上最難降的妖魔是什么乃沙? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任起趾,我火速辦了婚禮,結(jié)果婚禮上警儒,老公的妹妹穿的比我還像新娘训裆。我一直安慰自己,他們只是感情好蜀铲,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布边琉。 她就那樣靜靜地躺著,像睡著了一般记劝。 火紅的嫁衣襯著肌膚如雪变姨。 梳的紋絲不亂的頭發(fā)上田轧,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天还栓,我揣著相機(jī)與錄音骚秦,去河邊找鬼酌摇。 笑死瀑志,一個(gè)胖子當(dāng)著我的面吹牛汁果,可吹牛的內(nèi)容都是我干的湃望。 我是一名探鬼主播良漱,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼愧口,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼睦番!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耍属,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤托嚣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后厚骗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體示启,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年领舰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了夫嗓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迟螺。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖舍咖,靈堂內(nèi)的尸體忽然破棺而出矩父,到底是詐尸還是另有隱情,我是刑警寧澤排霉,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布窍株,位于F島的核電站,受9級(jí)特大地震影響攻柠,放射性物質(zhì)發(fā)生泄漏球订。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一瑰钮、第九天 我趴在偏房一處隱蔽的房頂上張望冒滩。 院中可真熱鬧,春花似錦浪谴、人聲如沸开睡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽士八。三九已至,卻和暖如春梁呈,著一層夾襖步出監(jiān)牢的瞬間婚度,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工官卡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝗茁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓寻咒,卻偏偏與公主長(zhǎng)得像哮翘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子毛秘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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

  • __block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用饭寺,...
    LZM輪回閱讀 3,291評(píng)論 0 6
  • 2.變量和基本類型 3.字符串、向量和數(shù)組 4.表達(dá)式 5.語句 2.變量和基本類型 c++的算術(shù)類型: 一個(gè)ch...
    暮落晴空閱讀 647評(píng)論 0 0
  • 2.1auto關(guān)鍵字 auto expr; 當(dāng)expr包含cv描述符的時(shí)候叫挟,比如const int a = 1;a...
    Teech閱讀 153評(píng)論 0 0
  • 項(xiàng)目地址 課程內(nèi)容 Part1 C++模板簡(jiǎn)介(An Introduction to C++ Template) ...
    偷天神貓閱讀 548評(píng)論 0 1
  • 技術(shù)交流QQ群:1027579432艰匙,歡迎你的加入! 一.static關(guān)鍵字的作用 1.靜態(tài)成員的特點(diǎn) 1.sta...
    CurryCoder閱讀 2,726評(píng)論 3 3