如何从T的数组中创建一个N T的元组?

时间:2022-09-16 12:53:58

If I have a constexpr array of N integers, how do I convert it to an appropriate constexpr std::tuple<...>?

如果我有一个N个整数的constexpr数组,我如何将它转换成合适的constexpr std::tuple<…>?

2 个解决方案

#1


16  

Here is a possible implementation for raw arrays:

这里有一个原始数组的可能实现:

#include<functional>

template<std::size_t... I, std::size_t N>
constexpr auto f(const int (&arr)[N], std::index_sequence<I...>) {
    return std::make_tuple(arr[I]...);
}

template<std::size_t N>
constexpr auto f(const int (&arr)[N]) {
    return f(arr, std::make_index_sequence<N>{});
}

int main() {
    constexpr int arr[] = { 0, 1, 2 };
    constexpr auto tup = f(arr);
    static_assert(std::get<0>(tup) == 0, "!");
    static_assert(std::get<1>(tup) == 1, "!");
    static_assert(std::get<2>(tup) == 2, "!");
}

The size of a constexpr array can be deduced at compile-time, so you don't have to explicitly specify it.
That size can be used internally to create a set of indices to get the elements out from the array and create the tuple on the fly.

constexpr数组的大小可以在编译时推断出来,所以不必显式地指定它。该大小可以在内部用于创建一组索引,以从数组中获取元素并动态创建tuple。


As mentioned in the comments, if you want to generalize a bit more and accept both raw arrays and std::arrays, you can do this:

正如在评论中提到的,如果您想要进一步推广并同时接受原始数组和std:::array,您可以这样做:

#include<functional>
#include<array>

template<std::size_t... I, typename U>
constexpr auto f(const U &arr, std::index_sequence<I...>) {
    return std::make_tuple(arr[I]...);
}

template<typename T, std::size_t N>
constexpr auto f(const T (&arr)[N]) {
    return f(arr, std::make_index_sequence<N>{});
}

template<typename T, std::size_t N>
constexpr auto f(const std::array<T, N> &arr) {
    return f(arr, std::make_index_sequence<N>{});
}

int main() {
    constexpr int arr1[] = { 0, 1, 2 };
    constexpr auto tup1 = f(arr1);
    static_assert(std::get<0>(tup1) == 0, "!");
    static_assert(std::get<1>(tup1) == 1, "!");
    static_assert(std::get<2>(tup1) == 2, "!");

    constexpr std::array<int, 3> arr2 = { 0, 1, 2 };
    constexpr auto tup2 = f(arr2);
    static_assert(std::get<0>(tup2) == 0, "!");
    static_assert(std::get<1>(tup2) == 1, "!");
    static_assert(std::get<2>(tup2) == 2, "!");
}

#2


2  

Converting an array into a tuple takes advantage of std::integer sequence, building up the array indices at compile time as the compiler invokes the helper function for 0..N.

将数组转换为元组将利用std::整数序列,在编译时构建数组索引,因为编译器将调用helper函数为0..N。

Here's the code which demonstrates this. http://coliru.stacked-crooked.com/a/b2d6c6ca1f5dc635

这是演示的代码。http://coliru.stacked-crooked.com/a/b2d6c6ca1f5dc635

////////////////////////////////////////////////////////////////////////////////////////////////////
// tuple_from_array
namespace detail {
template<typename T, std::size_t... Is>
auto constexpr tuple_from_array(T const& arr, std::index_sequence<Is...>)
{
  return std::make_tuple(arr[Is]...);
}

template<std::size_t N, typename V, typename T, std::size_t ...Is>
auto constexpr array_from_container(T const& c, std::index_sequence<Is...>)
{
  return std::array<V, N>{c[Is]...};
}

} // ns detail

template<typename T>
auto constexpr tuple_from_array(T const& arr)
{
  auto constexpr tup_size = std::tuple_size<std::decay_t<T>>::value;
  return detail::tuple_from_array(arr, std::make_index_sequence<tup_size>{});
}

template<typename T, std::size_t N>
auto constexpr tuple_from_array(T const (&arr)[N])
{
  return detail::tuple_from_array(arr, std::make_index_sequence<N>{});
}

// not safe
template<std::size_t N, typename T>
auto constexpr tuple_from_container(T const& c)
{
  using V = typename T::value_type;
  return tuple_from_array(detail::array_from_container<N, V>(c, std::make_index_sequence<N>{}));
}

edit: I combined skypjack@'s answer with my own to cover basic arrays as queried in the comments. I can't re-put this as my own answer for two days though :(

编辑:我把skypjack@的答案和我自己的答案结合起来,涵盖了评论中提出的基本数组。我不能再把这当作我两天的回答:

#1


16  

Here is a possible implementation for raw arrays:

这里有一个原始数组的可能实现:

#include<functional>

template<std::size_t... I, std::size_t N>
constexpr auto f(const int (&arr)[N], std::index_sequence<I...>) {
    return std::make_tuple(arr[I]...);
}

template<std::size_t N>
constexpr auto f(const int (&arr)[N]) {
    return f(arr, std::make_index_sequence<N>{});
}

int main() {
    constexpr int arr[] = { 0, 1, 2 };
    constexpr auto tup = f(arr);
    static_assert(std::get<0>(tup) == 0, "!");
    static_assert(std::get<1>(tup) == 1, "!");
    static_assert(std::get<2>(tup) == 2, "!");
}

The size of a constexpr array can be deduced at compile-time, so you don't have to explicitly specify it.
That size can be used internally to create a set of indices to get the elements out from the array and create the tuple on the fly.

constexpr数组的大小可以在编译时推断出来,所以不必显式地指定它。该大小可以在内部用于创建一组索引,以从数组中获取元素并动态创建tuple。


As mentioned in the comments, if you want to generalize a bit more and accept both raw arrays and std::arrays, you can do this:

正如在评论中提到的,如果您想要进一步推广并同时接受原始数组和std:::array,您可以这样做:

#include<functional>
#include<array>

template<std::size_t... I, typename U>
constexpr auto f(const U &arr, std::index_sequence<I...>) {
    return std::make_tuple(arr[I]...);
}

template<typename T, std::size_t N>
constexpr auto f(const T (&arr)[N]) {
    return f(arr, std::make_index_sequence<N>{});
}

template<typename T, std::size_t N>
constexpr auto f(const std::array<T, N> &arr) {
    return f(arr, std::make_index_sequence<N>{});
}

int main() {
    constexpr int arr1[] = { 0, 1, 2 };
    constexpr auto tup1 = f(arr1);
    static_assert(std::get<0>(tup1) == 0, "!");
    static_assert(std::get<1>(tup1) == 1, "!");
    static_assert(std::get<2>(tup1) == 2, "!");

    constexpr std::array<int, 3> arr2 = { 0, 1, 2 };
    constexpr auto tup2 = f(arr2);
    static_assert(std::get<0>(tup2) == 0, "!");
    static_assert(std::get<1>(tup2) == 1, "!");
    static_assert(std::get<2>(tup2) == 2, "!");
}

#2


2  

Converting an array into a tuple takes advantage of std::integer sequence, building up the array indices at compile time as the compiler invokes the helper function for 0..N.

将数组转换为元组将利用std::整数序列,在编译时构建数组索引,因为编译器将调用helper函数为0..N。

Here's the code which demonstrates this. http://coliru.stacked-crooked.com/a/b2d6c6ca1f5dc635

这是演示的代码。http://coliru.stacked-crooked.com/a/b2d6c6ca1f5dc635

////////////////////////////////////////////////////////////////////////////////////////////////////
// tuple_from_array
namespace detail {
template<typename T, std::size_t... Is>
auto constexpr tuple_from_array(T const& arr, std::index_sequence<Is...>)
{
  return std::make_tuple(arr[Is]...);
}

template<std::size_t N, typename V, typename T, std::size_t ...Is>
auto constexpr array_from_container(T const& c, std::index_sequence<Is...>)
{
  return std::array<V, N>{c[Is]...};
}

} // ns detail

template<typename T>
auto constexpr tuple_from_array(T const& arr)
{
  auto constexpr tup_size = std::tuple_size<std::decay_t<T>>::value;
  return detail::tuple_from_array(arr, std::make_index_sequence<tup_size>{});
}

template<typename T, std::size_t N>
auto constexpr tuple_from_array(T const (&arr)[N])
{
  return detail::tuple_from_array(arr, std::make_index_sequence<N>{});
}

// not safe
template<std::size_t N, typename T>
auto constexpr tuple_from_container(T const& c)
{
  using V = typename T::value_type;
  return tuple_from_array(detail::array_from_container<N, V>(c, std::make_index_sequence<N>{}));
}

edit: I combined skypjack@'s answer with my own to cover basic arrays as queried in the comments. I can't re-put this as my own answer for two days though :(

编辑:我把skypjack@的答案和我自己的答案结合起来,涵盖了评论中提出的基本数组。我不能再把这当作我两天的回答: