📜  如何在 C++ 中迭代 std::tuple 的元素

📅  最后修改于: 2021-10-28 03:00:22             🧑  作者: Mango

C++ 元组是一个容器,可以在其中存储多种类型的多个值。我们可以使用std::get()访问元组的元素,但std::get()始终采用常量变量参数,因此我们不能简单地使用循环遍历它。对于需要遍历元组所有元素的任务。喜欢打印所有元素。

下面是说明迭代元素元组的程序:

CPP14
// C++ program to iterate over the
// elements of an std::tuple
// using std:get()
#include 
#include 
#include 
 
// Driver Code
int main()
{
    // Declare a tuple and initialize
    // it using its constructor
    std::tuple
        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;
}


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


CPP
// C++ program to  iterated thorough
// all values. I equals number
// of values in tuple
#include 
#include 
#include 
 
using namespace std;
 
// WARNING: C++17 or above required
template 
contexpr void printTuple(tuple 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(tup) << " ";
 
        // Going for next element.
        printTuple(tup);
    }
}
 
// Driver Code
int main()
{
    // Initialize the tuple
    tuple tup("Geeks",
                                      "for",
                                      "Geeks");
 
    // Function call
    printTuple(tup);
 
    return 0;
}


CPP
// C++ program to  iterated thorough
// all values. I equals number
// of values in tuple
#include 
#include 
#include 
 
template 
void printTuple(std::tuple 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
        tup("Geeks", "for", "geeks");
 
    // Function call
    printTuple(tup);
    return 0;
}


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

当我们尝试遍历整个元组时,问题就出现了。因此,我们在这里有两种方法来遍历元组的值:

  1. 使用可变模板和元编程(不使用 std::apply)。
  2. 使用可变模板和 std::apply。

使用可变模板模板

可变模板用于传递打包在一个模板参数中的多个参数,并且可以稍后在函数内部扩展。下面是我们将如何遍历元组的所有元素。
下面是相同的实现:

CPP

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

使用 constexpr()函数和 if constexpr 表达式大大简化了这种情况,但仅从 C++17 开始可用。我也为此简化了代码,您可以在 C++17 中运行它。

下面是上述方法的实现:

CPP

// C++ program to  iterated thorough
// all values. I equals number
// of values in tuple
#include 
#include 
#include 
 
using namespace std;
 
// WARNING: C++17 or above required
template 
contexpr void printTuple(tuple 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(tup) << " ";
 
        // Going for next element.
        printTuple(tup);
    }
}
 
// Driver Code
int main()
{
    // Initialize the tuple
    tuple 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,所有这些函数都会被依次调用。这是模板元编程

注意:因此,您不能在 Geeksforgeeks IDE 上运行上述代码,您需要在另一个编译器上运行它。如果你想使用 C++14 或 C++11,你可以使用第一种方法。元组和模板仅在 C++11 中可用,因此不能使用旧版本。

使用可变模板和 std::apply()

  1. 首先,关于std::get()是什么的简单指南。 std::get()在元组元素上实现一些函数,将元组元素视为该函数的值。它接受一个函数f(x, y, z….) 和一个元组 (x, y, z…) 作为函数的参数,并返回 f 返回的值。
  2. 现在还有一两件事,关于可变参数的扩展,如果我们需要申请一个可变参数模板的所有值的一些函数,那么我们就做类似foo(TS)…,其中Ts是我们的可变参数模板,和Foo()是函数需要应用于打包在 Ts 中的所有值。这里函数“…”后的三个点表示该函数应用于可变参数模板的扩展。
  3. Lambda 函数是匿名函数,可以轻松声明和应用。它们的实现方式如下:
[&a, b, c] (int x, float &y) {
     
     // Function Body
}
  1. 这里x和y为参数,其中x是通过和y值传递通过引用的函数。而且,x、y 和 z 是将在函数内部出于某种目的使用的变量,因此它们被馈送到函数,这意味着它们将在函数的范围内可用。
    下面是相同的实现:

CPP

// C++ program to  iterated thorough
// all values. I equals number
// of values in tuple
#include 
#include 
#include 
 
template 
void printTuple(std::tuple 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
        tup("Geeks", "for", "geeks");
 
    // Function call
    printTuple(tup);
    return 0;
}
  1. 输出:
    下面是上面代码的输出:

注意: std::apply()仅在 C++17 中可用。所以,你不能在 Geeksforgeeks IDE 上运行这段代码,你需要在另一个编译器上运行它。如果你想使用 C++14 或 C++11,你可以使用第一种方法。元组和模板仅在 C++11 中可用,因此不能使用旧版本。

想要从精选的视频和练习题中学习,请查看C++ 基础课程,从基础到高级 C++ 和C++ STL 课程,了解语言和 STL。要完成从学习语言到 DS Algo 等的准备工作,请参阅完整的面试准备课程