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