通过将两个参数包的元素线程化为类型对来解包两个参数包

Unpacking two parameter packs by threading their elements to pairs of types

假设 N 用户指定的类型,我想要一个 return 长度 Nstd::tuple 的函数,其中每个元素都是通过函数构造的调用某些函数(如下面的 func 所示):

#include <tuple>
#include <utility>

template <typename T> 
T func(int x)
{
    return T();
}

template<typename... T, std::size_t... I> 
std::tuple<T...> build_tuple()
{
    // How do I write this in a generic way?
    return std::make_tuple(
        func<std::string>(0),
        func<int>(1),
        func<int>(2)
        );

    // This won't work, obviously
    // return std::make_tuple(func<T...>(I...));
}

int main() 
{
    build_tuple<std::string, int, int>();
}

本质上,我的问题是如何解压缩参数以获得类似于 "type0, 0"、"type1, 1" 等的东西,而不是 "type0, type1, ..., 0, 1, ...",如果这有意义的话。

这感觉像是一个常见问题,那么有惯用的解决方案吗?

如果 size_t 个参数是 0, 1, ...,您可以简单地使用额外的间接级别:

template<class Tuple, std::size_t... I> 
Tuple build_tuple_impl(std::index_sequence<I...>)
{
    return std::make_tuple(
        func<std::tuple_element_t<I, Tuple>>(I)...);
}

template<typename... Ts> 
auto build_tuple()
{
    using Tuple = std::tuple<Ts...>;
    return build_tuple_impl<Tuple>(std::make_index_sequence<sizeof...(Ts)>{});
}

// Usage:
auto t = build_tuple<std::string, int, int>();

更一般的情况:

template<class Tuple, std::size_t... Is, std::size_t... I> 
Tuple build_tuple_impl(std::index_sequence<Is...>, std::index_sequence<I...>)
{
    constexpr std::size_t is[] = {Is...};
    return std::make_tuple(
        func<std::tuple_element_t<I, Tuple>>(is[I])...);
}

template<typename... Ts, std::size_t... Is>
auto build_tuple(std::index_sequence<Is...> is)
{
    static_assert(sizeof...(Ts) == sizeof...(Is));

    using Tuple = std::tuple<Ts...>;
    return build_tuple_impl<Tuple>(is, std::make_index_sequence<sizeof...(Ts)>{});
}

// Usage:
auto t = build_tuple<std::string, int, int>(std::index_sequence<3, 4, 5>{});

不是说你不会写build_tuple<std::string, int, int, 3, 4, 5>()。其中一个序列应该被打包成一个类型。