Can someone please explain the “indices trick”?

前端 未结 1 1492
终归单人心
终归单人心 2020-11-29 07:38

I noticed the \"indices trick\" being mentioned in the context of pretty-printing tuples. It sounded interesting, so I followed the link.

Well, that did not go well.

相关标签:
1条回答
  • 2020-11-29 08:16

    The problem is: we have a std::tuple<T1, T2, ...> and we have some function f that we can to call on each element, where f returns an int, and we want to store those results in an array.

    Let's start with a concrete case:

    template <typename T> int f(T ) { return sizeof(T); }
    
    std::tuple<int, char, double> tup{42, 'x', 3.14};
    std::array<int, 3> arr{ f(std::get<0>(tup)), 
                            f(std::get<1>(tup)),
                            f(std::get<2>(tup)) );
    

    Except writing out all those gets is inconvenient and redundant at best, error-prone at worst.

    First we need to include the utility header for std::index_sequence and std::make_index_sequence:

    #include <utility>
    

    Now, let's say we had a type index_sequence<0, 1, 2>. We could use that to collapse that array initialization into a variadic pack expansion:

    template <typename Tuple, size_t... Indices>
    std::array<int, sizeof...(Indices)> 
    call_f_detail(Tuple& tuple, std::index_sequence<Indices...> ) {
        return { f(std::get<Indices>(tuple))... };
    }
    

    That's because within the function, f(std::get<Indices>(tuple))... gets expanded to f(std::get<0>(tuple)), f(std::get<1>(tuple)), f(std::get<2>(tuple)). Which is exactly what we want.

    The last detail of the problem is just generating that particular index sequence. C++14 actually gives us such a utility named make_index_sequence

    template <typename Tuple>
    std::array<int, std::tuple_size<Tuple>::value>
    call_f(Tuple& tuple) {
        return call_f_detail(tuple,
            // make the sequence type sequence<0, 1, 2, ..., N-1>
            std::make_index_sequence<std::tuple_size<Tuple>::value>{}
            );
    }
    

    whereas the article you linked simply explains how one might implement such a metafunction.

    Bare is probably something like, from Luc Danton's answer:

    template<typename T>
    using Bare = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
    
    0 讨论(0)
提交回复
热议问题