A classe std::tuple e suas funções-membro em C++

Jinku Hu 12 outubro 2023
  1. Use a função std::make_tuple para construir objetos std::tuple em C++
  2. Use um modelo de função para imprimir uma tupla de qualquer tamanho em C++
A classe std::tuple e suas funções-membro em C++

Este artigo demonstrará vários métodos para usar a classe std::tuple e suas funções de membro em C++.

Use a função std::make_tuple para construir objetos std::tuple em C++

A função std::tuple é o modelo de classe STL que implementa uma coleção de tamanho fixo de tipos heterogêneos. Geralmente, tuplas são frequentemente utilizadas em matemática para denotar a sequência finita de elementos, mas também estão associadas ao produto de diferentes tipos em linguagens de programação.

Em C++, existe uma classe semelhante, std::pair, que pode armazenar apenas dois objetos heterogêneos. A declaração de objeto std::tuple geralmente especifica os tipos dos quais a tupla consistirá e a ordem em que eles serão acessados. Esses tipos são especificados como parâmetros de modelo semelhantes a std::pair. O comando std::tuple pode ser inicializado com diferentes construtores. Ainda assim, neste caso, utilizamos a função std::make_tuple. O processo std::make_tuple leva um número variável de argumentos e tenta deduzir os tipos automaticamente. A função retorna o objeto std::tuple contendo os valores fornecidos.

No programa de exemplo a seguir, implementamos uma função chamada printTupleOfThree, que imprime a tupla de três valores. Observe que esta função de modelo não pode imprimir as tuplas com um número diferente de elementos. O comando printTupleOfThree pode ser chamado em tuplas com mais de três elementos, mas só produzirá os três primeiros. Portanto, como seria ineficiente definir funções sobrecarregadas para tuplas de tamanhos diferentes, precisamos resolver o problema usando uma abordagem diferente.

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

Resultado:

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

Use um modelo de função para imprimir uma tupla de qualquer tamanho em C++

A solução para o problema levantado na seção anterior é chamada de modelos variadic. O último é o recurso de modelos para aceitar um número variável de argumentos. Observe que printTuple é uma função de modelo variável que chama a função de membro print da classe TuplePrinter. O último é um modelo de classe que define uma única função de membro chamada print, mas lembre-se de que existem duas definições da classe TuplePrinter. Essa implementação é chamada de instanciação de template recursiva e é uma técnica conhecida em metaprogramação baseada em template.

A metaprogramação envolve métodos para utilizar o polimorfismo em tempo de compilação e é um tópico muito mais amplo do que este artigo pode tratar. Seria melhor se você consultasse um livro chamado C++ Templates - The Complete Guide para uma visão geral detalhada dos recursos de template e técnicas de metaprogramação que os utilizam. Como resultado, obtemos a função printTuple para ser compatível com objetos de tupla de tamanhos diferentes e pode imprimir todos os seus membros no fluxo 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;
}

Resultado:

(one, two, 1.1)
(one, two, 2, 1.1, 2.2)
Autor: 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