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

📅  最后修改于: 2021-05-30 02:18:58             🧑  作者: 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 contructor
    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 functiopn
            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()函数和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 functiopn
            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
    }
    

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

    输出:
    以下是上述代码的输出:

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

    想要从精选的最佳视频中学习和练习问题,请查看有关从基础到高级C++的C++基础课程以及有关语言和STL的C++ STL课程。要完成从学习语言到DS Algo等的更多准备工作,请参阅“完整面试准备课程”