在编译时产生相同类型的std::元组,给定其长度,由模板参数提供

Produce std::tuple of same type in compile time given its length by a template argument

本文关键字:参数 同类型 std 元组 编译      更新时间:2023-10-16

在c++中,我如何用int模板参数实现一个函数,该参数指示元组的长度,并产生一个具有该长度的std::元组?

func<2>() returns std::tuple<int, int>();
func<5>() returns std::tuple<int, int, int, int, int>().

这是一个使用别名模板的递归解决方案,它可以在c++ 11中实现:

template <size_t I,typename T> 
struct tuple_n{
    template< typename...Args> using type = typename tuple_n<I-1, T>::template type<T, Args...>;
};
template <typename T> 
struct tuple_n<0, T> {
    template<typename...Args> using type = std::tuple<Args...>;   
};
template <size_t I,typename T>  using tuple_of = typename tuple_n<I,T>::template type<>;

例如,如果我们想要"tuple of 3 doubles",我们可以写:

tuple_of<3, double> t;

使用index_sequence和助手类型别名可以生成所需的类型:

// Just something to take a size_t and give the type `int`
template <std::size_t>
using Integer = int;
// will get a sequence of Is = 0, 1, ..., N
template <std::size_t... Is>
auto func_impl(std::index_sequence<Is...>) {
    // Integer<Is>... becomes one `int` for each element in Is...
    return std::tuple<Integer<Is>...>{};
}
template <std::size_t N>
auto func() {
    return func_impl(std::make_index_sequence<N>{});
}

值得指出的是,在一般情况下,您可能会更好地使用std::array,(在您的情况下,您不能使用一个),但std::array可以表现得像一个元组,类似于std::pair

更新:既然你已经明确了你正在使用c++11而不是14+,你需要从某处获得index_sequence和相关的实现(这里是libc++的)。下面是带有显式返回类型的funcfunc_impl的c++ 11版本:

template <std::size_t... Is>
auto func_impl(std::index_sequence<Is...>) -> std::tuple<Integer<Is>...> {
  return std::tuple<Integer<Is>...>{};
}
template <std::size_t N>
auto func() -> decltype(func_impl(std::make_index_sequence<N>{})) {
  return func_impl(std::make_index_sequence<N>{});
}

普通的递归是你的朋友:

template<std::size_t N>
auto array_tuple() {
    return std::tuple_cat(std::tuple<int>{}, array_tuple<N-1>());
}
template<>
auto array_tuple<0>() {
    return std::tuple<>{};
}

如果您对c++ 14解决方案满意,那么Ryan的答案是可行的。

使用c++ 11,您可以执行以下操作(仍然基于index_sequence,但可以在c++ 11中实现):

template <size_t N, class T, class = std::make_index_sequence<N>>
struct n_tuple;
template <size_t N, class T, size_t... Is>
struct n_tuple<N, T, std::index_sequence<Is...>> {
    template <size_t >
    using ignore = T;
    using type = std::tuple<ignore<Is>...>;
};
template <size_t N, class T>
using n_tuple_t = typename n_tuple<N, T>::type;
与:

template <size_t N>
n_tuple_t<N, int> func() {
    return n_tuple_t<N, int>{};
}

这里有两个boost。hana解决方案(c++ 14):

//first
hana::replicate<hana::tuple_tag>(int{}, hana::size_c<2>);
//second
hana::cycle(std::make_tuple(int{}), hana::size_c<2>);

都产生大小为2的整元组,但它们产生的不是std::tuple s,而是hana::tuple s。

如果出于某种原因你真的想要一个元组而不是一个数组,你可以在数组上使用std::tuple_cat。我认为这种方法是最好的,因为它不需要任何第三方库,甚至不需要自己编写任何模板元编程代码。

std::array<int, 3> arr;
auto tup = std::tuple_cat(arr);
static_assert(std::is_same_v<decltype(tup), std::tuple<int, int, int>>);