c++之元組std::tuple常見用法


 

元組,c++11中引入的新的類型,可類比std::pair。 但是std::pair只能支持兩個元素。 理論上, 元組支持0~任意個元素。 

  本文演示環境: VS2015 up3

0、頭文件

#include <tuple>

 

1、創建和初始化

  1.1、創建一個空的元組, 創建時,需要指定元組的數據類型。

std::tuple<int, float, double, long, long long> first;

  1.2 、創建一個元組並初始化元組。  

1     std::string str_second_1("_1");
2     std::string str_second_2("_2");
3 
4     // 指定了元素類型為引用 和 std::string, 下面兩種方式都是可以的,只不過第二個參數不同而已
5     std::tuple<std::string, std::string> second_1(str_second_1, std::string("_2"));
6     std::tuple<std::string, std::string> second_2(str_second_1, str_second_2);

  1.3、創建一個元素是引用的元組

1     //3、創建一個元組,元組的元素可以被引用, 這里以 int 為例
2     int i_third = 3;
3     std::tuple<int&> third(std::ref(i_third));

  1.4、使用make_tuple創建元組

1     int i_fourth_1 = 4;
2     int i_fourth_2 = 44;
3     // 下面的兩種方式都可以
4     std::tuple<int, int> forth_1    = std::make_tuple(i_fourth_1, i_fourth_2);
5     auto forth_2                    = std::make_tuple(i_fourth_1, i_fourth_2);

  1.5、創建一個類型為引用的元組, 對元組的修改。 這里以 std::string為例

 1     std::string str_five_1("five_1");
 2     // 輸出原址值
 3     std::cout << "str_five_1 = " << str_five_1.c_str() << "\n";
 4 
 5     std::tuple<std::string&, int> five(str_five_1, 5);
 6     // 通過元組 對第一個元素的修改,str_five_1的值也會跟着修改,因為元組的第一個元素類型為引用。
 7     // 使用get訪問元組的第一個元素
 8     std::get<0>(five) = "five_2";
 9 
10     // 輸出的將是: five_2
11     std::cout << "str_five_1 = " << str_five_1.c_str() << "\n";

  輸出結果(VS2015 up3輸出):

 

2、計算元組的元素個數

  需要函數: std::tuple_size。 下面是一個例子, 

1     std::tuple<char, int, long, std::string> first('A', 2, 3, "4");
2         // 使用std::tuple_size計算元組個數
3         int i_count = std::tuple_size<decltype(first)>::value;
4         std::cout << "元組個數=" << i_count << "\n";

  輸出結果:

 

3、訪問元素

  訪問元組的元素,需要函數: std::get<index>(obj)。其中:【index】是元組中元素的下標,0 ,1 , 2, 3, 4,....     【obj】-元組變量。   

  一個例子:

1 std::tuple<char, int, long, std::string> second('A', 2, 3, "4");
2 int index = 0;
3 std::cout << index++ << " = " << std::get<0>(second) << "\n";
4 std::cout << index++ << " = " << std::get<1>(second) << "\n";
5 std::cout << index++ << " = " << std::get<2>(second) << "\n";
6 std::cout << index++ << " = " << std::get<3>(second).c_str() << "\n";

  輸出結果:

  【注意】元組不支持迭代訪問, 且只能通過索引(或者tie解包:將元組的中每一個元素提取到指定變量中)訪問, 且索引不能動態傳入。上面的代碼中,索引都是在編譯器編譯期間就確定了。 下面的演示代碼將會在編譯期間出錯。

for (int i = 0; i < 3; i++)
        std::cout << index++ << " = " << std::get<i>(second) << "\n";  // 無法通過編譯

  

4、獲取元素的類型

  獲取元組中某個元素的數據類型,需要用到另外一個類型: std::tuple_element 。 語法: std::tuple_element<index, tuple> 。 【index】-元組中元素的索引,【tuple】哪一個元組

  一個例子:

1 std::tuple<int, std::string> third(9, std::string("ABC"));
2 
3 // 得到元組第1個元素的類型,用元組第一個元素的類型聲明一個變量
4 std::tuple_element<1, decltype(third)>::type val_1;
5 
6 // 獲取元組的第一個元素的值
7 val_1 = std::get<1>(third);
8 std::cout << "val_1 = " << val_1.c_str() << "\n";

  輸出結果:

   用獲取元組第一個元素的類型聲明了一個變量,再對變量賦值。

 

5、使用 std::tie解包

  元組,可以看作一個包,類比結構體。 需要訪問元組的元素時,2 種方法: A、索引訪問,B、std::tie 。

  元組包含一個或者多個元素,使用std::tie解包: 首先需要定義對應元素的變量,再使用tie。 比如,元素第0個元素的類型時 char, 第1個元素類型時int,  那么, 需要定義 一個 char的變量和int的變量, 用來儲存解包元素的結果。 

  一個例子:

 1 std::tuple<char, int, long, std::string> fourth('A', 2, 3, "4");
 2 
 3 // 定義變量,保存解包結果
 4 char tuple_0    = '0';
 5 int tuple_1        = 0;
 6 long tuple_2    = 0;
 7 std::string tuple_3("");
 8 
 9 // 使用std::tie, 依次傳入對應的解包變量
10 std::tie(tuple_0, tuple_1, tuple_2, tuple_3) = fourth;
11 
12 // 輸出解包結果
13 std::cout << "tuple_0 = " << tuple_0 << "\n";
14 std::cout << "tuple_1 = " << tuple_1 << "\n";
15 std::cout << "tuple_2 = " << tuple_2 << "\n";
16 std::cout << "tuple_3 = " << tuple_3.c_str() << "\n";

  輸出結果:

  說到  std::tie , 看下 VS2015 up3中的定義:

1 template<class... _Types> inline
2     constexpr tuple<_Types&...>
3         tie(_Types&... _Args) _NOEXCEPT
4     {    // make tuple from elements
5     typedef tuple<_Types&...> _Ttype;
6     return (_Ttype(_Args...));
7     }

  接着 std::tie 解包。 如果一個元組,只需要取出其中特定位置上的元素,不用把每一個元素取出來, 怎么做? 

  比如: 只要索引為 偶數的元素。

  元組提供了類似占位符的功能: std::ignore 。滿足上面的需求,只需要在索引為奇數的位置填上 std::ignore 。 一個例子:

 1 std::tuple<char, int, long, std::string> fourth('A', 2, 3, "4");
 2         
 3 // 定義變量,保存解包結果
 4 char tuple_0    = '0';
 5 int tuple_1        = 0;
 6 long tuple_2    = 0;
 7 std::string tuple_3("");
 8 
 9 // 使用占位符
10 std::tie(tuple_0, std::ignore, tuple_2, std::ignore) = fourth;
11 
12 // 輸出解包結果
13 std::cout << "tuple_0 = " << tuple_0 << "\n";
14 std::cout << "tuple_1 = " << tuple_1 << "\n";
15 std::cout << "tuple_2 = " << tuple_2 << "\n";
16 std::cout << "tuple_3 = " << tuple_3.c_str() << "\n";

  輸出結果:

  

6、元組連接(拼接)

  使用 std::tuple_cat 執行拼接

  一個例子:

 1 std::tuple<char, int, double> first('A', 1, 2.2f);
 2 
 3 // 組合到一起, 使用auto, 自動推導
 4 auto second = std::tuple_cat(first, std::make_tuple('B', std::string("-=+")));
 5 // 組合到一起,可以知道每一個元素的數據類型時什么 與 auto推導效果一樣
 6 std::tuple<char, int, double, char, std::string> third = std::tuple_cat(first, std::make_tuple('B', std::string("-=+")));
 7 
 8 // 輸出合並后的元組內容
 9 int index = 0;
10 std::cout << index++ << " = " << std::get<0>(second) << "\n";
11 std::cout << index++ << " = " << std::get<1>(second) << "\n";
12 std::cout << index++ << " = " << std::get<2>(second) << "\n";
13 
14 std::cout << index++ << " = " << std::get<3>(second) << "\n";
15 std::cout << index++ << " = " << std::get<4>(second).c_str() << "\n";

  輸出結果:

 

7、遍歷

  這里將采用的時 遞歸遍歷,需要注意,考慮爆棧的情況。其實,tuple也是基於模板的STL容器。 因為其可以容納多個參數,且每個參數類型可不相同,遍歷輸出則涉及到參數展開的情況,這里以遞歸的方式實現遍歷, 核心代碼:

 1 template<typename Tuple, size_t N>
 2 struct tuple_show
 3 {
 4     static void show(const Tuple &t, std::ostream& os)
 5     {
 6         tuple_show<Tuple, N - 1>::show(t, os);
 7         os << ", " << std::get<N - 1>(t);
 8     }
 9 };
10 
11 
12 // 偏特性,可以理解為遞歸的終止
13 template<typename Tuple>
14 struct tuple_show < Tuple, 1>
15 {
16     static void show(const Tuple &t, std::ostream &os)
17     {
18         os <<  std::get<0>(t);
19     }
20 };
21 
22 
23 
24 // 自己寫個函數,調用上面的遞歸展開,
25 template<typename... Args>
26 std::ostream& operator << (std::ostream &os, const std::tuple<Args...>& t)
27 {
28     os << "[";
29     tuple_show<decltype(t), sizeof...(Args)>::show(t, os);
30     os << "]";
31 
32     return os;
33 }

  調用示例:

1     auto t1 = std::make_tuple(1, 'A', "-=+", 2);
2     std::cout << t1;

  輸出結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM