Jon*_*Mee 4 c++ recursion tuples metaprogramming range
我写了一个for_each为tupleS:
template <typename Tuple, typename F, size_t begin, size_t end>
enable_if_t<begin == end || tuple_size<Tuple>::value < end> for_each(Tuple&, F&&) {
}
template <typename Tuple, typename F, size_t begin = 0U, size_t end = tuple_size<Tuple>::value>
enable_if_t<begin < end && tuple_size<Tuple>::value >= end> for_each(Tuple& t, F&& f) {
f(get<begin>(t));
for_each<Tuple, F, begin + 1, end>(t, forward<F>(f));
}
Run Code Online (Sandbox Code Playgroud)
[ 实例 ]
但是Yakk对这个问题的回答给出了一个很好的例子,说明如何处理非递归地在所有tuple值上运行lambda :
namespace detail {
template<class F, class...Args>
void for_each_arg(F&& f, Args&&...args) {
using detail = int[];
static_cast<void>(detail{((f(std::forward<Args>(args))), void(), 0)..., 0});
}
}
template <typename F, typename Tuple>
void for_each_tuple_element(F&& f, Tuple&& t) {
return experimental::apply([&](auto&&...args) { detail::for_each_arg(forward<F>(f), decltype(args)(args)... ); }, forward<Tuple>(t));
}
Run Code Online (Sandbox Code Playgroud)
这需要apply.你可以在这里看到我对Yakk答案的简化:http://ideone.com/yAYjmw
我的问题是:有没有办法以某种方式改进for_each_tuple_element范围,避免我的代码引起的递归?我已经尝试构建tuple由范围定义的子集,但是如果不使用递归我似乎无法做到这一点,那么为什么不只是我的for_each呢?
您可以通过生成对std::get<Is>(t)...函数的一系列调用来避免递归,Is索引范围从begin最高到end-1.生成从给定索引开始的连续数字序列相当容易,因为它足以使起始点成为偏移量,然后将其添加到常规索引序列的每个项目中,例如:
std::get<begin + 0>(t), std::get<begin + 1>(t), ... std::get<begin + n>(t)
Run Code Online (Sandbox Code Playgroud)
其中序列的长度等于begin和之间的距离end.
#include <tuple>
#include <type_traits>
#include <utility>
#include <cstddef>
#include <limits>
template <std::size_t begin, typename Tuple, typename F, std::size_t... Is>
void for_each(Tuple&& t, F&& f, std::index_sequence<Is...>)
{
using expand = int[];
static_cast<void>(expand{ 0, (f(std::get<begin + Is>(std::forward<Tuple>(t))), void(), 0)... });
}
template <std::size_t begin = 0U, std::size_t end = std::numeric_limits<std::size_t>::max(), typename Tuple, typename F>
void for_each(Tuple&& t, F&& f)
{
for_each<begin>(std::forward<Tuple>(t), std::forward<F>(f)
, std::make_index_sequence<(end==std::numeric_limits<std::size_t>::max()?std::tuple_size<std::decay_t<Tuple>>::value:end)-begin>{});
}
Run Code Online (Sandbox Code Playgroud)
测试:
int main()
{
auto t = std::make_tuple(3.14, "Hello World!", -1);
auto f = [](const auto& i) { std::cout << i << ' '; };
for_each<1>(t, f);
for_each<1,3>(t, f);
for_each<0,2>(t, f);
}
Run Code Online (Sandbox Code Playgroud)
另外,请注意,函数模板的默认模板参数不必放在模板参数列表的末尾,因此,您可以避免丑陋的decltype(t), decltype(f)部分.这意味着end不能默认std::tuple_size<Tuple>::value(从那Tuple以后end),但此时你只需要一些默认的幻数.