如何在C ++ 11中迭代std :: tuple [英] How to iterate over a std::tuple in C++ 11
问题描述
我做了以下元组:
我想知道应该如何迭代它?有 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::array
s and std::pair
s. 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 ... $ c $的一些编译时改进。 c>调用。)
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屋!