我可以在这里避免模板递归吗? [英] Can I avoid template recursion here?
问题描述
我为 tuple
写了 for_each
:
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));
}
[ Live Example ]
但 Yakk's回答这个问题给出了如何处理对所有 tuple
值非递归处理运行lambda的精彩示例:
But Yakk's answer to this question gives a wonderful example of how to handle running a lambda on all tuple
values non-recursively:
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));
}
这需要 apply
。您可以在这里看到我对简介 Yakk 的答案: http://ideone.com/yAYjmw
我的问题是:是否有办法以某种方式改造 for_each_tuple_element
有一个范围,避免我的代码引起的递归?我已经尝试构建元组的子集
由范围定义,但是我不能这样做,而不使用递归,然后为什么不只是我的 for_each
?
My question is this: Is there a way to somehow retrofit for_each_tuple_element
with a range, avoiding the recursion that my code incurs? I've tried constructing the subset of the tuple
defined by the range, but I can't seem to do that without using recursion, and then why not just my for_each
?
推荐答案
可以通过生成对 std :: get< Is>(t) code>函数,
是
索引范围从开始
到 end-1
。从给定索引开始生成连续数字序列是相当容易的,因为它足以使起始点具有偏移量,然后将其添加到常规索引序列的每个项目,例如:
You could avoid recursion by generating a sequence of calls to the std::get<Is>(t)...
function, with Is
indices ranging from begin
up to end-1
. It's fairly easy to generate a sequence of consecutive numbers starting at a given index, as it's enough to make the starting point an offset that is then added to each item of a regular index sequence, e.g.:
std::get<begin + 0>(t), std::get<begin + 1>(t), ... std::get<begin + n>(t)
其中序列的长度等于 begin
和 end
。
where the length of the sequence is equal to the distance between begin
and 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>{});
}
测试:
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);
}
此外,请注意,功能模板的默认模板参数不必放在模板参数列表的末尾,因此,可以避免丑陋的 decltype(t),decltype(f)
部分。这意味着 end
不能默认为 std :: tuple_size< Tuple> :: value
c> Tuple 在结束
之后),但在这一点上你需要的是一些默认的魔法数字。
Also, note that defaulted template parameters of a function template don't have to be placed at the end of a template parameter list, hence, you can avoid the ugly decltype(t), decltype(f)
part. This implies that end
cannot be defaulted to std::tuple_size<Tuple>::value
(since Tuple
goes after end
), but at this point all you need is some default magic number.
这篇关于我可以在这里避免模板递归吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!