【问题标题】:How to access type's index in the template type parameter pack?如何访问模板类型参数包中的类型索引?
【发布时间】:2021-04-28 18:56:14
【问题描述】:

我想在将类型参数包扩展为 std::tuple<...> 时访问类型的索引。

例如,给定一个 <int, double, float> 类型包,我想构建一个如下所示的 std::tuple<...>

std::tuple<std::array<int,0>, std::array<double,1>, std::array<float, 2>>
//                     ^  ^                ^    ^                ^    ^
//                     T  I                T    I                T    I

这是一个几乎完全符合我要求的实现,但它仅适用于大小为 3 的类型包(请参阅 hack 旁边的评论)。如何解决此问题以独立于 TT...s 大小?

#include <tuple>
#include <utility>
#include <array>
#include <iostream>

template <typename... TT>
struct Foo {
    template <std::size_t... Indices>
    struct Baz {
       std::tuple<std::array<TT,Indices>...> baz;
    };
    Baz<0,1,2> bar; // <<<=== Here is the hack: I make a fixed-size pack; I want it to match TT...
};

int main() {
    Foo<int,double,float> foo;
    std::cout << std::get<0>(foo.bar.baz).size() << std::endl;
    std::cout << std::get<1>(foo.bar.baz).size() << std::endl;
    std::cout << std::get<2>(foo.bar.baz).size() << std::endl;
    return 0;
}

Live demo.

【问题讨论】:

  • 我只是好奇。我在过去看到过类似的请求,我问自己这些是否只是更多相关代码的示例,有人有兴趣解决的难题,或者这种数据结构是否有实际用途。
  • @2b-t 这不是我使用的真实数据结构。我选择了std::array,因为它有一个数字模板参数和一个类型模板参数,所以我不需要在示例中显示我自己的模板类型。
  • 哦,这确实有道理!非常感谢您的解释。绝对是我最近遇到的最有趣的可变参数模板相关问题之一:我实际上不知道您实际上可以使用两个参数包来执行 std::array&lt;T,I&gt;...

标签: c++ c++11 templates


【解决方案1】:

你在嵌套两包的正确轨道上。您现在需要的是一个std::integer_sequence,它可以让您创建所需的包,而不是通过Baz&lt;0,1,2&gt; bar; 对其进行硬编码。

基本思想是定义一个函数模板,它在包上接受std::integer_sequence&lt;size_t,I...&gt; 参数化并用std::make_integer_sequence&lt;size_t,N&gt; 调用它,这样包I... 可以从单个数字N 推导出来,那么它是只是折叠:

#include <tuple>
#include <utility>
#include <array>
#include <iostream>
#include <utility>
#include <type_traits>

template <typename...Ts>
struct foo {
    static const size_t N = sizeof...(Ts);
    template <size_t ... I>
    static auto helper(std::integer_sequence<size_t,I...>){
        return std::tuple<std::array<Ts,I>...>{};
    }
    using type = decltype(helper(std::make_integer_sequence<size_t,N>{}));
};

int main() {
    std::cout << std::is_same< std::tuple<std::array<int,0>, std::array<double,1>, std::array<float, 2>>,
                 foo<int,double,float>::type >::value;
}

Live Demo

【讨论】:

  • 非常有趣...我实际上不知道你可以做类似std::array&lt;Ts,I&gt;... 的事情!感谢分享!
  • @2b-t: OP 已经使用std::array&lt;Ts, Indices&gt;... BTW。
  • @Jarod42 是的,我后来才注意到这一点。我看到你已经回答了类似的问题,例如std::tuple 而不是 std::array。我看到我还有很多东西要向你们学习。 :) 你知道有人会用这种复杂的数据结构做什么吗?我见过很多类似的问题,所以它似乎没有我最初想象的那么奇特。
  • @2b-t 是的,你应该感谢 OP ;)。如果他们没有使用并行包,我无法想出这个答案。我不知道 OP 在他们的真实代码中到底有什么,我也很好奇,但回答这个问题并不重要,因为他们的例子是 mcve 足以添加缺失的部分。我怀疑他们实际上想要一个大小为 0 的数组
  • @2b-t 我试着写出代表自己的答案。如果这是给操作员的私人信函,那么可能不是“你在嵌套两包的正确轨道上......”我会写“哇,这真的很酷,让我看看我能不能摆弄一下使用代码,直到我通过反复试验让它以某种方式工作”:P
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 2014-11-27
相关资源
最近更新 更多