C++ 中的 std::tuple 類及其成員函式

Jinku Hu 2023年10月12日
  1. 使用 std::make_tuple 函式在 C++ 中構造 std::tuple 物件
  2. 在 C++ 中使用函式模板列印任意大小的元組
C++ 中的 std::tuple 類及其成員函式

本文將演示在 C++ 中使用 std::tuple 類及其成員函式的多種方法。

使用 std::make_tuple 函式在 C++ 中構造 std::tuple 物件

函式 std::tuple 是實現固定大小的異構型別集合的 STL 類别範本。通常,元組在數學中經常被用來表示元素的有限序列,但它也與程式語言中不同型別的乘積相關聯。

在 C++ 中,有一個類似的類,std::pair,它只能儲存兩個異構物件。std::tuple 物件宣告通常指定元組將包含的型別以及它們將被訪問的順序。這些型別被指定為類似於 std::pair 的模板引數。std::tuple 命令可以用不同的建構函式初始化。儘管如此,在這種情況下,我們還是使用 std::make_tuple 函式。std::make_tuple 過程採用可變數量的引數並嘗試自動推斷型別。該函式返回包含給定值的 std::tuple 物件。

在下面的示例程式中,我們實現了一個名為 printTupleOfThree 的函式,它列印三個值的元組。請注意,此模板函式無法列印具有不同元素數量的元組。printTupleOfThree 命令可以在具有三個以上元素的元組上呼叫,但它只會輸出其中的前三個。因此,由於為不同大小的元組定義過載函式效率低下,我們需要使用不同的方法來解決問題。

#include <iostream>
#include <tuple>
#include <vector>

using std::cout;
using std::endl;
using std::string;
using std::tuple;
using std::vector;

template <typename Tuple>
void printTupleOfThree(Tuple t) {
  cout << "(" << std::get<0>(t) << ", " << std::get<1>(t) << ", "
       << std::get<2>(t) << ")" << endl;
}

int main() {
  std::vector<string> v1{"one", "two", "three", "four", "five", "six"};
  std::vector<int> v2 = {1, 2, 3, 4, 5, 6};
  std::vector<float> v3 = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};

  auto t1 = std::make_tuple(v1[0], v1[1], v2[0]);
  auto t2 = std::make_tuple(v1[0], v1[1], v2[0], v3[0], v3[1]);
  printTupleOfThree(t1);
  printTupleOfThree(t2);

  return EXIT_SUCCESS;
}

輸出:

(one, two, 1)
(one, two, 2)

在 C++ 中使用函式模板列印任意大小的元組

上一節中提出的問題的解決方案稱為可變引數模板。後者是模板接受可變數量引數的特性。請注意,printTuple 是一個可變引數模板函式,它呼叫 TuplePrinter 類的 print 成員函式。後者是一個類别範本,它定義了一個名為 print 的成員函式,但請記住,TuplePrinter 類有兩個定義。這種實現稱為遞迴模板例項化,它是基於模板的超程式設計中的一種已知技術。

超程式設計涉及利用編譯時多型性的方法,這是一個比本文所能處理的更大的主題。最好參考一本名為 C++ 模板–完整指南 的書,以詳細瞭解模板特性和使用它們的超程式設計技術。結果,我們使 printTuple 函式與不同大小的元組物件相容,並且可以將其所有成員列印到 cout 流。

#include <iostream>
#include <tuple>
#include <vector>

using std::cout;
using std::endl;
using std::string;
using std::tuple;
using std::vector;

template <class Tuple, std::size_t N>
struct TuplePrinter {
  static void print(const Tuple& t) {
    TuplePrinter<Tuple, N - 1>::print(t);
    std::cout << ", " << std::get<N - 1>(t);
  }
};

template <class Tuple>
struct TuplePrinter<Tuple, 1> {
  static void print(const Tuple& t) { std::cout << std::get<0>(t); }
};

template <class... Args>
void printTuple(const std::tuple<Args...>& t) {
  std::cout << "(";
  TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
  std::cout << ")" << endl;
}

int main() {
  std::vector<string> v1{"one", "two", "three", "four", "five", "six"};
  std::vector<int> v2 = {1, 2, 3, 4, 5, 6};
  std::vector<float> v3 = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};

  auto t1 = std::make_tuple(v1[0], v1[1], v3[0]);
  auto t2 = std::make_tuple(v1[0], v1[1], v2[1], v3[0], v3[1]);
  printTuple(t1);
  printTuple(t2);

  return EXIT_SUCCESS;
}

輸出:

(one, two, 1.1)
(one, two, 2, 1.1, 2.2)
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 創辦人。Jinku 在機器人和汽車行業工作了8多年。他在自動測試、遠端測試及從耐久性測試中創建報告時磨練了自己的程式設計技能。他擁有電氣/ 電子工程背景,但他也擴展了自己的興趣到嵌入式電子、嵌入式程式設計以及前端和後端程式設計。

LinkedIn Facebook