我可以在这里避免模板递归吗?

Jon*_*Mee 4 c++ recursion tuples metaprogramming range

我写了一个for_eachtupleS:

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呢?

Pio*_*cki 5

您可以通过生成对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)

DEMO

另外,请注意,函数模板的默认模板参数不必放在模板参数列表的末尾,因此,您可以避免丑陋的decltype(t), decltype(f)部分.这意味着end不能默认std::tuple_size<Tuple>::value(从那Tuple以后end),但此时你只需要一些默认的幻数.