Как перебирать элементы std :: tuple в C ++
Кортеж 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
Проблема возникает, когда мы пытаемся перебрать весь кортеж. Итак, у нас есть два метода для перебора значений кортежа:
- Использование шаблонов Variadic и метапрограммирования (без использования std :: apply).
- Использование шаблонов 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 () :
- Во-первых, простое руководство о том, что такое std :: get () . std :: get () реализует некоторую функцию для элементов кортежей, рассматривая элементы кортежей как значения для этой функции. Он принимает одну функцию f (x, y, z….) И кортеж (x, y, z…), которые являются аргументами функции, и возвращает значение, возвращаемое функцией f.
- Теперь еще кое-что о вариативном расширении: если нам нужно применить некоторую функцию ко всем значениям вариативного шаблона, мы делаем это как foo (Ts)…, где Ts - наш вариативный шаблон, а foo () - функция, которая необходимо применять ко всем значениям, упакованным в Ц. Здесь три точки после функции «…» означают, что функция применяется к расширению вариативного шаблона.
- Лямбда-функции - это анонимные функции, которые можно легко объявить и применить. Реализованы они как:
[& a, b, c] (int x, float & y) { // Тело функции }
- Здесь 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; } |
- Выход:
Ниже приведен вывод вышеуказанного кода:
Примечание: std :: apply () доступна только в C ++ 17. Итак, вы не можете запустить этот код в IDE Geeksforgeeks, вам нужно запустить его на другом компиляторе. Если вы хотите использовать C ++ 14 или C ++ 11, вы можете использовать первый метод. Кортежи и шаблоны доступны только в C ++ 11, поэтому старые версии использовать нельзя.