Как перебирать элементы std :: tuple в C ++

Опубликовано: 29 Декабря, 2021

Кортеж C ++ - это контейнер, который может хранить в себе несколько значений нескольких типов. Мы можем получить доступ к элементам кортежа с помощью std :: get () , но std :: get () всегда принимает постоянный параметр переменной, поэтому мы не можем просто перебирать его с помощью цикла. Для задач, требующих перебора всех элементов кортежа. напечатать все элементы.

Ниже приведена программа, иллюстрирующая перебор кортежа элементов:

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;
}
Выход:
 Значения кортежа: Компьютерщики для компьютерных фанатов
Значения кортежа (изменено): Привет, добро пожаловать в Geeksforgeeks

Проблема возникает, когда мы пытаемся перебрать весь кортеж. Итак, у нас есть два метода для перебора значений кортежа:

  1. Использование шаблонов Variadic и метапрограммирования (без использования std :: apply).
  2. Использование шаблонов Variadic и std :: apply.

Использование вариативных шаблонов и шаблонов :

Шаблоны с переменным числом аргументов используются для передачи нескольких аргументов, упакованных в один аргумент шаблона, который может быть расширен позже внутри функции. Вот как мы пройдемся по всем элементам кортежа.
Ниже приведена реализация того же самого:

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;
}
Выход:
 Вундеркинды для гиков

Этот случай очень упрощается с помощью функции constexpr () и выражений if constexpr, но они доступны только начиная с C ++ 17. Я тоже использую упрощенный код для этого, вы можете запустить его на C ++ 17.

Ниже представлена реализация описанного выше подхода:

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

Выход:
Ниже приведен вывод вышеуказанного кода:

Объяснение:

Требование std :: get () - постоянный индекс, а не переменная. Мы всегда можем указать постоянный номер для функции-шаблона, «I» здесь - постоянный номер для функции. Итак, у нас будет n + 1 экземпляров функции print_num () , где n - размер кортежа, каждый из которых имеет «I» как постоянное число для себя. Таким образом, экземпляры этих функций будут наподобие print_tuple, print_tuple,…. И print_tuple, и все эти функции будут вызываться последовательно. Это метапрограммирование шаблона

Примечание: Итак, вы не можете запустить приведенный выше код в IDE Geeksforgeeks, вам нужно запустить его на другом компиляторе. Если вы хотите использовать C ++ 14 или C ++ 11, вы можете использовать первый метод. Кортежи и шаблоны доступны только в C ++ 11, поэтому старые версии использовать нельзя.

Использование шаблонов Variadic и std :: apply () :

  1. Во-первых, простое руководство о том, что такое std :: get () . std :: get () реализует некоторую функцию для элементов кортежей, рассматривая элементы кортежей как значения для этой функции. Он принимает одну функцию f (x, y, z….) И кортеж (x, y, z…), которые являются аргументами функции, и возвращает значение, возвращаемое функцией f.
  2. Теперь еще кое-что о вариативном расширении: если нам нужно применить некоторую функцию ко всем значениям вариативного шаблона, мы делаем это как foo (Ts)…, где Ts - наш вариативный шаблон, а foo () - функция, которая необходимо применять ко всем значениям, упакованным в Ц. Здесь три точки после функции «…» означают, что функция применяется к расширению вариативного шаблона.
  3. Лямбда-функции - это анонимные функции, которые можно легко объявить и применить. Реализованы они как:
 [& a, b, c] (int x, float & y) {
     
     // Тело функции
}
  1. Здесь x и y - аргументы функции, где x передается по значениям, а y - по ссылке. И x, y и z - это переменные, которые будут использоваться внутри функции для некоторых целей, поэтому они передаются в функцию, что означает, что они будут доступны внутри области действия функции.
    Ниже приведена реализация того же самого:

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. Выход:
    Ниже приведен вывод вышеуказанного кода:

Примечание: std :: apply () доступна только в C ++ 17. Итак, вы не можете запустить этот код в IDE Geeksforgeeks, вам нужно запустить его на другом компиляторе. Если вы хотите использовать C ++ 14 или C ++ 11, вы можете использовать первый метод. Кортежи и шаблоны доступны только в C ++ 11, поэтому старые версии использовать нельзя.

Хотите учиться на лучших видео и практических задачах, ознакомьтесь с базовым курсом C ++ для базового и продвинутого уровня C ++ и курсом C ++ STL для языка и STL. Чтобы завершить подготовку от изучения языка к DS Algo и многому другому, см. Полный курс подготовки к собеседованию .