C++11::遍歷tuple中的元素
結尾有彩蛋:-D。
閱讀本文之前你需要懂至少一下知識:
tuple
tuple,元組型別。標頭檔案<tuple>,tuple是一個固定大小的不同型別(異質,heterogeneous)值的集合(這一點是tuple與其他常規STL容器的最大不同,即它可以同時存放不同型別的資料),是泛化的std::pair(也即std::pair是tuple的一個特例,長度受限為2)。這裡插一句嘴,tuple元組型別是python原生的基本資料型別(C++新標準也引入了lambda函式物件,似乎語言之間有一種互相學習走向趨同的趨勢),關於python中的元組型別,可參閱我的Python 基礎——list的成員方法。
decltype
C++11引入的新的關鍵字,用以根據變數推導變數的資料型別
非型別模板引數
關於非型別模板引數詳細的內容請參見之前的模板系列,<C++基礎——非型別模板引數>
在設計tuple的遍歷程式之前,我們不妨先進行std::pair的列印工作:
// #include <utility>
cout << make_pair("InsideZhang", 23) << end;
// ("InsideZhang", 23)
為了實現上述的功能,我們需要過載<<
運算子。
template<typename T1, typename T2>
std::ostream& pair_print(std::ostream& os, const pair<T1, T2>& p)
{
return os << "(" << p.first << ", " << p.second << ")";
}
當我們試圖仿照上例的形式實現對tuple的遍歷輸出時:
template<typename... Args>
std::ostream& operator<<(std::ostream& os, const std::tuple<Args...>& t)
{
os << "(" << std::get<0>(t);
for (size_t i = 1; i < sizeof...(Args) << ++i)
os << ", " << std::get<i>(t);
return os << "]";
}
int main(int, char**)
{
cout << make_tuple("InsideZhang", 23, "HeNan") << endl;
// 編譯出錯,區域性變數i不可作為非型別模板引數
return 0;
}
這時我們便需要單獨把每一位的索引拿出來作為非型別模板引數進行遞迴呼叫:
template<typename Tuple>
void tuple_print(const Tuple& t, size_t N, std::ostream& os)
{
if (N != 1)
tuple_print(t, N-1, os);
os << std::get<N-1>(t);
}
以上的程式碼, 也即通過引數傳遞的方式進行的非型別模板引數的賦值,仍然編譯不通過。非型別模板引數必須在編譯時即為常量表示式。
template<typename Tuple, size_t N>
void tuple_print(const Tuple& t, std::ostream& os)
{
if (N != 1)
tuple_print<Tuple, N-1>(t, os);
os << std::get<N-1>(t);
}
這樣做似乎也編譯不通過,具體為什麼,一時也想不出來,大家有什麼思路和想法不妨提供一下。
以下是一個通行的解決方案:
template<typename Tuple, size_t N>
struct tuple_print
{
static void print(const Tuple& t, std::ostream& os)
{
tuple_print<Tuple, N-1>::print(t, os);
os << ", " << std::get<N-1>(t);
}
};
// 類别範本的特化版本
template<typename Tuple>
struct tuple_print<Tuple, 1>
{
static void print(const Tuple& t, std::ostream& os)
{
os << "(" << std::get<0>(t);
}
};
// operator<<
template<typename... Args>
std::ostream& operaotr<<(std::ostream& os, const std::tuple<Args...>& t)
{
tuple_print<decltype(t), sizeof...(Args)>::print(t, os);
return os << ")";
}
客戶端程式碼:
auto t1 = std::make_tuple("InsideZhang", 23, "HeNan");
auto t2 = std::make_tuple("InsideLi", 23, "AnHui");
// tuple_cat() 元組拼接
// 呼叫operator<< 運算子過載
std::cout << std::tuple_cat(t1, t2) << std::endl;
// (InsideZhang, 23, HeNan, InsideLi, 23, AnHui)
因為tuple類沒有過載
operator[]
運算子,很難像其他容器和資料額結構一樣進行簡潔的索引動作,只能通過一個全域性的std::get<size_t>(t)
進行操作。
tuple class最早公開於Boost程式庫。在那兒,tuple可以將元素寫至output stream,不知道為什麼C++標準庫不支援這一性質,而是需要我們花費一些精力手動完成這一工作。
#include <iostream>
#include <boost\tuple\tuple_io.hpp>
int main(int, char**)
{
std::cout << boost::make_tuple("InsideZhang", 23, "HeNan") << std::endl;
return 0;
}
References
相關文章
- DOM元素的遍歷
- 關於二叉樹的前序遍歷、中序遍歷、刪除元素、插入元素二叉樹
- for in語句遍歷陣列中的元素陣列
- js如何遍歷陣列中的元素JS陣列
- jQuery 元素操作——遍歷元素jQuery
- C++11 tupleC++
- Jquery之遍歷元素jQuery
- vector容器1(新增元素,遍歷元素)
- javascript如何遍歷陣列中的每一個元素JavaScript陣列
- 遍歷聚合物件中的元素——迭代器模式(四)物件模式
- 遍歷聚合物件中的元素——迭代器模式(三)物件模式
- jquery遍歷子元素的寫法jQuery
- 遍歷List 同時 remove 元素REM
- 現代c++模板超程式設計:遍歷tupleC++程式設計
- jQuery遍歷函式,javascript中的each遍歷jQuery函式JavaScript
- java陣列如何遍歷全部的元素Java陣列
- JS中的遍歷JS
- JavaScript 中的遍歷JavaScript
- 二叉樹的建立、前序遍歷、中序遍歷、後序遍歷二叉樹
- HashSet 新增/遍歷元素原始碼分析原始碼
- PHP 遍歷元素並分批處理PHP
- 利用jQuery如何遍歷指定的li元素集合jQuery
- python 切片獲取list、tuple中的元素Python
- Python字典的遍歷,包括key遍歷/value遍歷/item遍歷/Python
- 二叉樹建立,前序遍歷,中序遍歷,後序遍歷 思路二叉樹
- JavaScript遍歷陣列每一個元素JavaScript陣列
- javascript使用for in語句遍歷陣列元素JavaScript陣列
- 遍歷檔案Java中遍歷出指定目錄中的所有檔案Java
- Python中list的遍歷Python
- Java中Map的遍歷方法Java
- JavaScript 中的遍歷詳解JavaScript
- 如何遍歷Map中的物件物件
- Python優雅遍歷字典刪除元素的方法Python
- puppeteer 頁面爬取例項(元素遍歷)
- javascript遍歷陣列元素程式碼例項JavaScript陣列
- js的map遍歷和array遍歷JS
- 面試中很值得聊的二叉樹遍歷方法——Morris遍歷面試二叉樹
- JavaScript中遍歷的幾種方法JavaScript