有人可以解释一下“指数技巧"吗?

2022-01-19 00:00:00 tuples indices c++ c++11 variadic-templates

我注意到在漂亮打印元组的上下文中提到了索引技巧".听起来很有趣,所以我关注了 链接.

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. I understood the question, but could really not follow what was going on. Why do we even need indices of anything? How do the different functions defined there help us? What is 'Bare'? etc.

有人可以为参数包和可变元组方面的专家详细介绍该内容吗?

Can someone give a play-by-play of that thing for the less-than-experts on parameter packs and variadic tuples?

推荐答案

问题是:我们有一个 std::tuple 并且我们有一些函数f 我们可以在每个元素上调用,其中 f 返回一个 int,我们希望将这些结果存储在一个数组中.

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)) );

除了写出所有这些 get 之外,充其量是不方便和多余的,最坏的情况是容易出错.

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

首先我们需要包含 std::index_sequencestd::make_index_sequence 的实用程序头:

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

#include <utility>

现在,假设我们有一个类型 index_sequence<0, 1, 2>.我们可以使用它来将该数组初始化折叠为可变参数包扩展:

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))... };
}

这是因为在函数中,f(std::get(tuple))... 被扩展为 f(std::get<0>(tuple))、f(std::get<1>(tuple))、f(std::get<2>(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.

问题的最后一个细节就是生成特定的索引序列.C++14 实际上给了我们这样一个名为 make_index_sequence

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 可能类似于 Luc Danton 的回答:

template<typename T>
using Bare = typename std::remove_cv<typename std::remove_reference<T>::type>::type;

相关文章