如何在C ++ 11中迭代std :: tuple [英] How to iterate over a std::tuple in C++ 11

查看:81
本文介绍了如何在C ++ 11中迭代std :: tuple的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做了以下元组:

我想知道应该如何迭代它?有 tupl_size(),但是在阅读文档时,我不知道如何使用它。我也有搜索,但是问题似乎在 Boost :: tuple 周围。

I want to know how should I iterate over it? There is tupl_size(), but reading the documentation, I didn't get how to utilize it. Also I have search SO, but questions seem to be around Boost::tuple .

auto some = make_tuple("I am good", 255, 2.1);


推荐答案

这是尝试破坏对元组的迭代

Here is an attempt to break down iterating over a tuple into component parts.

首先,该函数表示按顺序执行一系列操作。请注意,尽管据我所知它是合法的C ++ 11,但许多编译器仍难以理解:

First, a function that represents doing a sequence of operations in order. Note that many compilers find this hard to understand, despite it being legal C++11 as far as I can tell:

template<class... Fs>
void do_in_order( Fs&&... fs ) {
  int unused[] = { 0, ( (void)std::forward<Fs>(fs)(), 0 )... }
  (void)unused; // blocks warnings
}

接下来,该函数需要 std :: tuple ,并提取访问每个元素所需的索引。这样,我们以后就可以完善前进。

Next, a function that takes a std::tuple, and extracts the indexes required to access each element. By doing so, we can perfect forward later on.

作为附带的好处,我的代码支持 std :: pair std :: array 迭代:

As a side benefit, my code supports std::pair and std::array iteration:

template<class T>
constexpr std::make_index_sequence<std::tuple_size<T>::value>
get_indexes( T const& )
{ return {}; }

肉和土豆:

template<size_t... Is, class Tuple, class F>
void for_each( std::index_sequence<Is...>, Tuple&& tup, F&& f ) {
  using std::get;
  do_in_order( [&]{ f( get<Is>(std::forward<Tuple>(tup)) ); }... );
}

和面向公众的界面:

template<class Tuple, class F>
void for_each( Tuple&& tup, F&& f ) {
  auto indexes = get_indexes(tup);
  for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f) );
}

而它声明元组它适用于 std :: array s和 std :: pair s。它还将所述对象的r / l值类别转发到它调用的功能对象。另外请注意,如果您的自定义类型上有一个免费函数 get< N> ,并且您覆盖了 get_indexes ,高于 for_each 的对象将适用于您的自定义类型。

while it states Tuple it works on std::arrays and std::pairs. It also forward the r/l value category of said object down to the function object it invokes. Also note that if you have a free function get<N> on your custom type, and you override get_indexes, the above for_each will work on your custom type.

如前所述, do_in_order 尽管许多编译器不支持整洁,因为它们不喜欢将未经扩展的参数包扩展为参数包的lambda。

As noted, do_in_order while neat isn't supported by many compilers, as they don't like the lambda with unexpanded parameter packs being expanded into parameter packs.

我们可以内联 do_in_order 在这种情况下

We can inline do_in_order in that case

template<size_t... Is, class Tuple, class F>
void for_each( std::index_sequence<Is...>, Tuple&& tup, F&& f ) {
  using std::get;
  int unused[] = { 0, ( (void)f(get<Is>(std::forward<Tuple>(tup)), 0 )... }
  (void)unused; // blocks warnings
}

这不会花费太多的冗长,但是我个人发现在我看来, do_in_order 的工作原理的影子魔术可以通过内联进行隐藏。

this doesn't cost much verbosity, but I personally find it less clear. The shadow magic of how do_in_order works is obscured by doing it inline in my opinion.

index_sequence (和支持模板)是一种C ++ 14功能,可以用C ++ 11编写。在堆栈溢出时找到这样的实现很容易。是一个体面的O(lg(n))深度实现,如果我正确阅读注释,它可能是至少对实际gcc make_integer_sequence 进行一次迭代(这些注释还指出了围绕消除 sizeof ... 调用。)

index_sequence (and supporting templates) is a C++14 feature that can be written in C++11. Finding such an implementation on stack overflow is easy. A current top google hit is a decent O(lg(n)) depth implementation, which if I read the comments correctly may be the basis for at least one iteration of the actual gcc make_integer_sequence (the comments also point out some further compile-time improvements surrounding eliminating sizeof... calls).

或者我们可以这样写:

template<class F, class...Args>
void for_each_arg(F&&f,Args&&...args){
  using discard=int[];
  (void)discard{0,((void)(
    f(std::forward<Args>(args))
  ),0)...};
}

然后:

template<size_t... Is, class Tuple, class F>
void for_each( std::index_sequence<Is...>, Tuple&& tup, F&& f ) {
  using std::get;
  for_each_arg(
    std::forward<F>(f),
    get<Is>(std::forward<Tuple>(tup))...
  );
}

避免手动扩展,但可以在更多编译器上进行编译。我们通过 auto& i 参数传递 Is

Which avoids the manual expand yet compiles on more compilers. We pass the Is via the auto&&i parameter.

在C ++ 1z中,我们还可以将 std :: apply for_each_arg 函数对象一起使用离开索引摆弄。

In C++1z we can also use std::apply with a for_each_arg function object to do away with the index fiddling.

这篇关于如何在C ++ 11中迭代std :: tuple的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆