我可以在这里避免模板递归吗? [英] Can I avoid template recursion here?

查看:117
本文介绍了我可以在这里避免模板递归吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为 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);
}

DEMO

此外,请注意,功能模板的默认模板参数不必放在模板参数列表的末尾,因此,可以避免丑陋的 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屋!

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