【问题标题】:Can someone please explain the "indices trick"?有人可以解释一下“指数技巧”吗?
【发布时间】:2015-10-06 10:34:47
【问题描述】:

我注意到在漂亮打印元组的上下文中提到了“索引技巧”。听起来很有趣,所以我关注了the link

好吧,那并不顺利。我理解这个问题,但真的无法理解发生了什么。为什么我们甚至需要任何东西的索引?那里定义的不同功能对我们有何帮助?什么是“裸”?等等

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

【问题讨论】:

    标签: c++ c++11 tuples variadic-templates indices


    【解决方案1】:

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

    让我们从一个具体的案例开始:

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

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

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

    #include <utility>
    

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

    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&lt;Indices&gt;(tuple))... 被扩展为 f(std::get&lt;0&gt;(tuple)), f(std::get&lt;1&gt;(tuple)), f(std::get&lt;2&gt;(tuple))。这正是我们想要的。

    问题的最后一个细节就是生成特定的索引序列。 C++14 实际上给了我们这样一个名为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>{}
            );
    }
    

    而您链接的文章只是解释了如何实现这样的元功能。

    Bare 可能类似于来自Luc Danton's answer

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

    【讨论】:

    • Bare 似乎类似于remove_reference_t。请注意,OP 链接页面上的代码通过转发引用获取元组,因此Tuple 可以是引用类型,而tuple_size 不适用于引用类型。 (从技术上讲,不需要remove_cvtuple_size 应该可以在 cv-qualified tuples 上正常工作。)
    • 很好的答案,像往常一样。我在this answer 中找到了Bare 的可能定义,它似乎类似于decay_t
    • 在call_f_detail的定义中,你的意思不是f(std::get&lt;Indices&gt;(tuple)...)而不是f(std::get&lt;Indices&gt;(tuple))...吗?
    • 另外,还有一个更重要的问题——为什么我们需要灵活地“支持”任何索引序列?索引 不是包含不必要的冗余吗?
    • @einpoklum 不,我没有。包扩展通过将表达式置于... 的左侧来工作,因此第一个表达式应为f(std::get&lt;0&gt;(tuple), std::get&lt;1&gt;(tuple), ...) 而不是f(std::get&lt;0&gt;(tuple)), f(std::get&lt;1&gt;(tuple)), ...。我们想对每个元素单独调用f,而不是对所有元素一起调用。请参阅 my answer here 了解扩展不同的包表达式
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-22
    • 2016-12-12
    • 2011-02-09
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多