La classe std::tuple et ses fonctions membres en C++

Jinku Hu 12 octobre 2023
  1. Utilisez la fonction std::make_tuple pour construire des objets std::tuple en C++
  2. Utiliser un modèle de fonction pour imprimer un tuple de n’importe quelle taille en C++
La classe std::tuple et ses fonctions membres en C++

Cet article présentera plusieurs méthodes d’utilisation de la classe std::tuple et de ses fonctions membres en C++.

Utilisez la fonction std::make_tuple pour construire des objets std::tuple en C++

La fonction std::tuple est le modèle de classe STL qui implémente une collection de taille fixe de types hétérogènes. Généralement, les tuples sont fréquemment utilisés en mathématiques pour désigner la séquence finie d’éléments, mais ils sont également associés au produit de différents types dans les langages de programmation.

En C++, il existe une classe similaire, std::pair, qui ne peut stocker que deux objets hétérogènes. La déclaration d’objet std::tuple spécifie généralement les types à partir desquels le tuple sera composé et l’ordre dans lequel ils seront accédés. Ces types sont spécifiés en tant que paramètres de modèle similaires à std::pair. La commande std::tuple peut être initialisée avec différents constructeurs. Pourtant, dans ce cas, nous utilisons la fonction std::make_tuple. Le processus std::make_tuple prend un nombre variable d’arguments et essaie d’en déduire les types automatiquement. La fonction retourne l’objet std::tuple contenant les valeurs données.

Dans l’exemple de programme suivant, nous implémentons une fonction nommée printTupleOfThree, qui imprime le tuple de trois valeurs. Notez que cette fonction de modèle ne peut pas imprimer les tuples avec un nombre différent d’éléments. La commande printTupleOfThree peut être appelée sur des tuples avec plus de trois éléments, mais elle n’affichera que les trois premiers d’entre eux. Donc, comme il serait inefficace de définir des fonctions surchargées pour des tuples de tailles différentes, nous devons résoudre le problème en utilisant une approche différente.

#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;
}

Production:

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

Utiliser un modèle de fonction pour imprimer un tuple de n’importe quelle taille en C++

La solution au problème soulevé dans la section précédente est appelée modèles variadiques. Ce dernier est la particularité des modèles d’accepter un nombre variable d’arguments. Notez que printTuple est une fonction modèle variadique qui appelle la fonction membre print de la classe TuplePrinter. Ce dernier est un modèle de classe qui définit une fonction membre unique appelée print, mais rappelez-vous qu’il existe deux définitions de la classe TuplePrinter. Cette implémentation est appelée instanciation de modèle récursive, et c’est une technique connue dans la métaprogrammation basée sur des modèles.

La métaprogrammation implique des méthodes pour utiliser le polymorphisme à la compilation, et c’est un sujet bien plus vaste que cet article ne peut traiter. Il serait préférable que vous vous référiez à un livre intitulé Modèles C++ - Le guide complet pour un aperçu détaillé des fonctionnalités des modèles et des techniques de métaprogrammation les utilisant. En conséquence, nous obtenons que la fonction printTuple soit compatible avec les objets tuple de différentes tailles et puisse imprimer tous leurs membres dans le flux 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;
}

Production:

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

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook