C++多元組Tuple使用方法?你熟悉嗎?快來(lái)看看吧
前言
tuple 是類似于pair的模板。每個(gè)pair的成員類型都不相同,但每個(gè)pair都恰好有兩個(gè)成員。不同tuole類型的也不相同,但一個(gè)tuple可以有任意數(shù)量的成員。每個(gè)確定的tuple類型的成員數(shù)目是固定的,但一個(gè)tuple類型的成員數(shù)目可以與另一個(gè)tuple類型不同。
當(dāng)我們希望將一些數(shù)據(jù)組合成單一對(duì)象,但又不想麻煩地定義一個(gè)新數(shù)據(jù)來(lái)表示這些數(shù)據(jù)時(shí),tuple是非常有用的。
例如我們可以構(gòu)造一個(gè)tuple
- tuple<const char*, int>tp = make_tuple(sendPack,nSendSize);
這個(gè)tuple等價(jià)于一個(gè)結(jié)構(gòu)體
- struct A
- {
- char* p;
- int len;
- };
用tuple
還有一種方法也可以創(chuàng)建元組,用std::tie,它會(huì)創(chuàng)建一個(gè)元組的左值引用。
- auto tp = return std::tie(1, "aa", 2);
tp的類型實(shí)際是:
- std::tuple<int&,string&, int&>
tuple初印象
tuple支持如下的操作
- std::tuple<T1, T2, ...TN> t; //創(chuàng)建一個(gè)空的tuple對(duì)象(使用默認(rèn)構(gòu)造),它對(duì)應(yīng)的元素分別是T1和T2...Tn類型,采用值初始化。
- std::tuple<T1, T2, ...TN> t2(v1, v2, ... vn); //創(chuàng)建一個(gè)tuple對(duì)象,它的元素分別是T1和T2 ...Tn類型; 每個(gè)成員用對(duì)應(yīng)的vi進(jìn)行初始化
- std::tuple<T1&> t3(ref&); // tuple的元素類型可以是一個(gè)引用
像pair一樣也可以通過(guò)make_tuple進(jìn)行創(chuàng)建一個(gè)tuple對(duì)象,tuple的類型從初始值的類型推斷
- std::make_tuple(v1, v2);
返回t的第i個(gè)數(shù)據(jù)成員的引用:如果t是一個(gè)左值,結(jié)果是一個(gè)左值引用;否則,結(jié)果是一個(gè)右值引用。此外tuple的所有成員都是pulic的。
- get<i>(t)
我們可以將tuple看作一個(gè)“快速而隨意”的數(shù)據(jù)結(jié)構(gòu)。
定義和初始化tuple
當(dāng)我們定義一個(gè)std::tuple時(shí),需要指出每個(gè)成員的類型。
- tuple<size_t,size_t,size_t> threeD; //三個(gè)成員都被設(shè)置為0
- tuple<string,vector<doble>,int ,list<int>> someVal("constans",{3.14,2.718},42,{0,1,2,3,4,5});
當(dāng)我們創(chuàng)建一個(gè)std::tuple對(duì)象時(shí),可以使用tuple的默認(rèn)構(gòu)造函數(shù),它會(huì)對(duì)每個(gè)成員進(jìn)行值初始化;也可以向上面someVal初始化一樣,為每個(gè)成員提供一個(gè)初始值,此時(shí)的構(gòu)造函數(shù)是explicit的,因此必須使用直接初始化方法。
- tuple<size_t,size_t,size_t> htreeD = {1,2,3};
- tuple<size_t,size_t,size_t> htreeD(1,2,3);
類似make_pair函數(shù),標(biāo)準(zhǔn)庫(kù)定義了make_tuple函數(shù),我們還可以使用它來(lái)生成std::tuple對(duì)象。
- auto item = mak_tuple("0-999-78345-x",3,20.00);
類似make_pair,make_tuple函數(shù)使用初始值的類型來(lái)推斷tuple的類型。在上面示例中,item是一個(gè)tuple,類型為tuple
訪問(wèn)tuple的成員
一個(gè)pair總是有兩個(gè)成員,這樣標(biāo)準(zhǔn)庫(kù)就可以為他們命名(first和second),但是這種命名方法不適用于tuple,因?yàn)橐粋€(gè)tuple的類型的成員數(shù)目是沒有限制的。因?yàn)?,tuple的成員都是未命名的。要訪問(wèn)一個(gè)tuple的成員,就要使用一個(gè)名為get的標(biāo)準(zhǔn)庫(kù)函數(shù)模板。為了使用get,我們必須指定一個(gè)顯示模板實(shí)參,它指出我們想要訪問(wèn)第幾個(gè)成員。我們傳遞給get一個(gè)tuple對(duì)象,它返回指定成員的引用。
- auto book = get<0>(iterm); //返回iterm的第一個(gè)成員
- auto cnt = get<0>(iterm); //返回iterm的第二個(gè)成員
- auto price = get<0>(iterm)/cnt; //返回iterm的第三個(gè)成員
尖括號(hào)中的值必須是一個(gè)整型常量表達(dá)式,與平時(shí)一樣,我們從0開始計(jì)數(shù),意味著get<0>是第一個(gè)成員。
如果不知道tuple準(zhǔn)確的類型細(xì)節(jié)信息,可以用兩個(gè)輔助類模板查詢tuole的成員的數(shù)量和類型:
1.一個(gè)類模板,可以通過(guò)一個(gè)tuple類型初始化,它有一個(gè)名為value的public constexpr static數(shù)據(jù)類型,類型為size_t,表示給定tuple類型中成員數(shù)量
- tuple_element<i,tupleType>::type
2.一個(gè)類模板,可以通過(guò)一個(gè)整型常量和一個(gè)tuple類型來(lái)初始化。它有一個(gè)名為type的public成員,表示給定tuple類型中指定的類型
- tuple_size<tupleType>::value
通過(guò)這兩個(gè)類模板我們可以獲得我們需要的tuple變量的成員數(shù)量和類型
- typedef decltype(item) trans;//trans是item的類型
- size_t sz = tuple_size< trans>::value;//返回trans類型對(duì)象中成員的數(shù)量
- tuple_element<1,trans>::type cnt ; // cnt 為 item第二個(gè)成員變量類型 int型
- cnt = get<1>(item);
為了使用tuple_size或tuple_element,我們需要知道一個(gè)tuple對(duì)象的類型。與往常一樣,確定一個(gè)對(duì)象的類型的最簡(jiǎn)單的方法就是使用decltype,在typedef decltype(item) trans;中,我們使用decltype來(lái)為item定義一個(gè)類型別名,用它來(lái)實(shí)例化這兩個(gè)模板。
tuple_size有一個(gè)名為value的public static數(shù)據(jù)成員,它表示給定tuple中成員的數(shù)量。 tuple_element模板除了一個(gè)tuple類型外,還接受一個(gè)索引值。它有一個(gè)名為type的public類型成員,表示給定tuple類型中指定成員類型。類似get,tuple_element所使用的索引也是從0開始計(jì)數(shù)的。
std::tuple的關(guān)系和相等運(yùn)算符的行為類似容器的對(duì)應(yīng)操作。這些運(yùn)算符逐對(duì)比較左側(cè)tuple和右側(cè)tuple的成員。只有兩個(gè)tuple具有相同數(shù)量的成員時(shí),我們才可以比較它們。而且,為了使用tuple的相等或不等運(yùn)算符,對(duì)每對(duì)成員使用==運(yùn)算符必須都是合法的;為了使用關(guān)系運(yùn)算符,對(duì)每對(duì)成員使用 < 必須都是合法的。
關(guān)系和相等運(yùn)算符:當(dāng)兩個(gè)tuole具有相同數(shù)量的成員且成員對(duì)應(yīng)相等時(shí),兩個(gè)才tuple相同。
- tuple<string,string> duo("1","2");
- tuple<size_t,size_t> twoD(1,2);
- bool b = (duo == twoD); // 錯(cuò)誤,不能比較size_t 和 string
- tuple<size_t,size_t,size_t> threeD(1,2,3);
- b = (duo == threeD); // 錯(cuò)誤,成員數(shù)量不同
- tuple<size_t,size_t> origin(0,0);
- b = (origin < twoD); // 正確:b為true
由于tuple定義了<和==運(yùn)算符,我們可以將tuple序列傳遞給算法,并且可以在無(wú)序容器中將tuple作為關(guān)鍵字類型。
利用tie進(jìn)行解包元素的值
如同pair一樣也是可以通過(guò)tie進(jìn)行解包tuple的各個(gè)元素的值。如下tuple對(duì)象有4個(gè)元素,通過(guò)tie解包將會(huì)把這4個(gè)元素的值分別賦值給tie提供的4個(gè)變量中。
- int main(int argc, char **argv) {
- std::tuple<std::string, int, std::string, int> tp;
- tp = std::make_tuple("Sven", 25, "Shanghai", 21);
- // 定義接收變量
- std::string name;
- std::string addr;
- int ages;
- int areaCode;
- std::tie(name, ages, addr, areaCode) = tp;
- std::cout << "Output: " << '\n';
- std::cout << "name: " << name <<", ";
- std::cout << "addr: " << addr << ", ";
- std::cout << "ages: " << ages << ", ";
- std::cout << "areaCode: " << areaCode << '\n';
- return 0;
- }
輸出結(jié)果:
name: Sven, addr: Shanghai, ages: 25, areaCode: 21
但有時(shí)候tuple包含的多個(gè)元素時(shí)只需要其中的一個(gè)或兩個(gè)元素,如此可以通過(guò)std::ignore進(jìn)行變量占位,這樣將會(huì)忽略提取對(duì)應(yīng)的元素??梢孕薷纳鲜隼蹋?/p>
- std::tie(name, ages, std::ignore, std::ignore) = tp;
std::tuple中元素是被緊密地存儲(chǔ)的(位于連續(xù)的內(nèi)存區(qū)域),而不是鏈?zhǔn)浇Y(jié)構(gòu)。
如何遍歷tuple成員
N表示tuple中的第N個(gè)元素
- #include <iostream>
- #include <tuple>
- #include <string>
- using namespace std;
- template<typename Tuple, int N = std::tuple_size<Tuple>::value>
- struct Printer
- {
- static void log(Tuple& t) {
- Printer<Tuple, N - 1>::log(t);
- using type = typename std::tuple_element<N - 1, Tuple>::type;
- std::string ts = typeid(type).name();
- type& v = std::get<N - 1>(t);
- std::cout << ts << ":" << v << std::endl;
- }
- };
- template<typename Tuple>
- struct Printer<Tuple, 1>
- {
- static void log(Tuple& t) {
- using type = typename std::tuple_element<0, Tuple>::type;
- std::string ts = typeid(type).name();
- type& v = std::get<0>(t);
- std::cout << ts << ":" << v << std::endl;
- }
- };
- int main() {
- std::tuple<int, bool, string> t = std::forward_as_tuple(11, true, "ok");
- Printer<std::tuple<int, bool, string>>::log(t);
- return 1;
- }
tuple做返回相關(guān)作用
使用tuple返回多個(gè)值,tuple的一個(gè)常見用途就是從一個(gè)函數(shù)返回多個(gè)值。
返回tuple的函數(shù)
- tuple<int, string> fun()
- {
- // 用make_tuple來(lái)構(gòu)造一個(gè)tuple
- return make_tuple(1024, "tuple",'3');
- }
使用函數(shù)返回的tuple
- auto tp = fun();
- auto id = std::get<0>(tp);
- auto name= std::get<1>(tp);
- auto num = std::get<2>(tp);
本文轉(zhuǎn)載自微信公眾號(hào)「羽林君」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系羽林君公眾號(hào)。