Cómo iterar sobre los elementos de un std::tuple en C++

Una tupla de C++ es un contenedor que puede almacenar múltiples valores de múltiples tipos en él. Podemos acceder a los elementos de la tupla usando std::get() , pero std::get() siempre toma un parámetro de variable constante, por lo que no podemos simplemente iterarlo usando un bucle. Para tareas que requieren iterar a través de todos los elementos de la tupla. como imprimir todos los elementos.

A continuación se muestra el programa para ilustrar la iteración sobre una tupla de elementos:
 

CPP14

// C++ program to iterate over the
// elements of an std::tuple
// using std:get()
#include <iostream>
#include <string>
#include <tuple>
 
// Driver Code
int main()
{
    // Declare a tuple and initialize
    // it using its constructor
    std::tuple<std::string, std::string,
               std::string>
        tup("Geeks", "for", "Geeks");
    std::cout << "Values of tuple: ";
 
    // std::get is used to access
    // the value of tuple.
    std::cout << std::get<0>(tup)
              << " " << std::get<1>(tup)
              << " " << std::get<2>(tup)
              << std::endl;
 
    // Make the tuple using
    // std::make_tuple function
    tup = std::make_tuple("Hey", "Welcome to",
                          "Geeksforgeeks");
 
    // Print tuple
    std::cout << "Values of tuple(Modified): ";
    std::cout << std::get<0>(tup) << " "
              << std::get<1>(tup) << " "
              << std::get<2>(tup)
              << std::endl;
 
    return 0;
}
Producción: 

Values of tuple: Geeks for Geeks
Values of tuple(Modified): Hey Welcome to Geeksforgeeks

 

El problema surge cuando tratamos de iterar a través de toda la tupla. Entonces, tenemos dos métodos aquí, para iterar a través de los valores de una tupla: 
 

  1. Uso de plantillas Variadic y metaprogramación (sin uso de std::apply).
  2. Uso de plantillas Variadic y std::apply.

Usando Plantillas Variádicas y Plantilla :

Las plantillas variádicas se usan para pasar múltiples argumentos empaquetados en un argumento de plantilla, y eso se puede expandir más tarde dentro de la función. Así es como revisaremos todos los elementos de una tupla.
A continuación se muestra la implementación del mismo:
 

CPP

// C++ program to  iterated thorough
// all values. I equals number
// of values in tuple
#include <iostream>
#include <string>
#include <tuple>
 
using namespace std;
 
// Function to iterate through all values
// I equals number of values in tuple
template <size_t I = 0, typename... Ts>
typename enable_if<I == sizeof...(Ts),
                   void>::type
printTuple(tuple<Ts...> tup)
{
    // If iterated through all values
    // of tuple, then simply return.
    return;
}
 
template <size_t I = 0, typename... Ts>
typename enable_if<(I < sizeof...(Ts)),
                   void>::type
printTuple(tuple<Ts...> tup)
{
 
    // Print element of tuple
    cout << get<I>(tup) << " ";
 
    // Go to next element
    printTuple<I + 1>(tup);
}
 
// Driver Code
int main()
{
    // Creating the tuple
    tuple<string, string, string> tup("Geeks",
                                      "for",
                                      "Geeks");
 
    // Function call
    printTuple(tup);
    return 0;
}
Producción: 

Geeks for Geeks

 

Este caso se simplifica mucho usando la función constexpr() y las expresiones if constexpr, pero solo están disponibles desde C++17 en adelante. También soy un código simplificado para eso, puede ejecutarlo en C++ 17.

A continuación se muestra la implementación del enfoque anterior:
 

CPP

// C++ program to  iterated thorough
// all values. I equals number
// of values in tuple
#include <iostream>
#include <string>
#include <tuple>
 
using namespace std;
 
// WARNING: C++17 or above required
template <size_t I = 0, typename... Ts>
contexpr void printTuple(tuple<Ts...> tup)
{
    // If we have iterated through all elements
    if
        constexpr(I == sizeof...(Ts))
        {
            // Last case, if nothing is left to
            // iterate, then exit the function
            return;
        }
    else {
        // Print the tuple and go to next element
        cout << get<I>(tup) << " ";
 
        // Going for next element.
        printTuple<I + 1>(tup);
    }
}
 
// Driver Code
int main()
{
    // Initialize the tuple
    tuple<string, string, string> tup("Geeks",
                                      "for",
                                      "Geeks");
 
    // Function call
    printTuple(tup);
 
    return 0;
}

Salida: 
A continuación se muestra la salida del código anterior: 
 

Explicación: 
 

El requisito de std::get() es un índice constante, sin variables. Siempre podemos especificar un número constante para una función de plantilla, «I» aquí es un número constante para la función. Entonces, tendremos n+1 instanciaciones de la función print_num() , donde n es el tamaño de la tupla, cada una tiene “I” como un número constante para sí misma. Entonces, las instancias de estas funciones serán como print_tuple, print_tuple, … e print_tuple, y todas estas funciones se llamarán en secuencia. Esta es la metaprogramación de plantillas

Nota: Por lo tanto, no puede ejecutar el código anterior en el IDE de Geeksforgeeks, debe ejecutarlo en otro compilador. Si desea utilizar C++14 o C++11, puede utilizar el primer método. Las tuplas y las plantillas solo están disponibles en C++ 11, por lo que no se pueden usar versiones anteriores.

Usando Plantillas Variádicas y std::apply() : 
 

  1. Primero, una guía simple sobre qué es std::get() . std::get() implementa alguna función en elementos de tuplas, considerando elementos de tuplas como valores para esa función. Toma una función f(x, y, z….) y una tupla (x, y, z…) que son argumentos para la función, y devuelve el valor devuelto por f.
  2. Ahora una cosa más, sobre la expansión variádica, si necesitamos aplicar alguna función en todos los valores de una plantilla variádica, entonces lo hacemos como foo(Ts)…, donde Ts es nuestra plantilla variádica, y foo() es la función que debe aplicarse en todos los valores empaquetados en Ts. Aquí, tres puntos después de la función «…» significa que la función se aplica a la expansión de la plantilla variádica.
  3. Las funciones Lambda son funciones anónimas, que se pueden declarar y aplicar fácilmente. Se implementan como: 
     
[&a, b, c] (int x, float &y) {
     
     // Function Body
}
  1. Aquí x e y son argumentos de la función donde x se pasa por valores e y por referencia. Y, x, y y z son variables que se usarán dentro de la función para algún propósito, por lo que se alimentan a la función, lo que significa que estarán disponibles dentro del alcance de la función.
    A continuación se muestra la implementación del mismo:
     

CPP

// C++ program to  iterated thorough
// all values. I equals number
// of values in tuple
#include <iostream>
#include <string>
#include <tuple>
 
template <typename... Ts>
void printTuple(std::tuple<Ts...> tup)
{
 
    // Getting size of tuple
    std::size_t length = sizeof...(Ts);
 
    // Using std::apply to print elements
    std::apply(
 
        // A lambda function
        [length](auto const&... ps) {
            std::cout << "[ ";
            int k = 0;
 
            // Variadic expansion used.
            ((std::cout << ps
                        << (++k == length ? "" : "; ")),
             ...);
 
            std::cout << " ]";
        },
        tuple);
}
 
// Driver Code
int main()
{
    // Initialize the tuple
    std::tuple<std::string,
               std::string, std::string>
        tup("Geeks", "for", "geeks");
 
    // Function call
    printTuple(tup);
    return 0;
}
  1. Salida: 
    A continuación se muestra la salida del código anterior: 
     

Nota: std::apply() solo está disponible desde C++17. Por lo tanto, no puede ejecutar este código en el IDE de Geeksforgeeks, debe ejecutarlo en otro compilador. Si desea utilizar C++14 o C++11, puede utilizar el primer método. Las tuplas y las plantillas solo están disponibles en C++ 11, por lo que no se pueden usar versiones anteriores.

Publicación traducida automáticamente

Artículo escrito por vikram2000b y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *