【问题标题】:How do I create a tuple of N T's from an array of T?如何从 T 的数组中创建 N T 的元组?
【发布时间】:2016-12-18 11:14:00
【问题描述】:

如果我有一个N 整数的constexpr 数组,如何将其转换为适当的constexpr std::tuple<...>

【问题讨论】:

  • 您的数组是原始数组还是std::array 还是什么?
  • 既然已经有了数组,为什么还要tuple

标签: c++ arrays tuples c++14


【解决方案1】:

以下是原始数组的可能实现:

#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, "!");
}

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


如 cmets 中所述,如果您想更概括一点并接受原始数组和std::arrays,您可以这样做:

#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, "!");
}

【讨论】:

  • 我喜欢这个答案,它有一个更干净/更纤薄的界面。谢谢!
  • 我将您的答案与我自己的答案结合起来,涵盖了基本数组和 std::array
  • @Short 我不会像你对std::array 那样做。如果你愿意,我也可以更新我的答案以涵盖它们。
  • 谢谢,基于此,我现在能够让我的更清洁。
  • @Short 你为什么要复制另一个答案来整合你的?这没有多大意义。它们不必相同。
【解决方案2】:

将数组转换为元组利用std::integer sequence,在编译器调用 0..N 的辅助函数时在编译时构建数组索引。

这是演示这一点的代码。 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>{}));
}

编辑:我将 skypjack@ 的答案与我自己的答案结合起来,以涵盖在 cmets 中查询的基本数组。不过,这两天我不能把这个作为我自己的答案:(

【讨论】:

  • 总是鼓励发布有用的问答。但是“代码转储”的答案并不是质量的缩影。我建议你编辑它并附上解释。
  • 如何实现“运行时零开销”?
  • constexpr 函数在编译时将数组转换为元组。抱歉,我更新了示例和代码链接以将元组实例化为 constexpr 值。
  • 将内部细节作为模板参数公开给用户不是好的做法:如果参数存在,用户开始使用和滥用它。这里也没有必要,因为您可以使用 index_sequence_for 代替。
  • @StoryTeller 你的权利,我用更多关于 std::integer_sequence 扩展的细节更新了我的答案。
猜你喜欢
  • 2017-10-04
  • 1970-01-01
  • 2021-12-27
  • 2017-02-26
  • 2022-01-13
  • 1970-01-01
  • 2011-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多