将std :: tuple转换为std :: array C++ 11

use*_*ser 18 c++ arrays tuples c++11

如果我有std::tuple<double, double, double>(类型是同类的),是否有转换为的股票函数或构造函数std::array<double>

编辑::我能够使用递归模板代码(我在下面发布的草稿答案).这是处理这个问题的最佳方法吗?这似乎会有一个库存函数......或者如果你对我的答案有所改进,我会很感激.我会留下未回答的问题(毕竟,我想要一个方法,而不仅仅是一种可行的方式),并且更愿意选择别人的[希望更好]答案.

谢谢你的建议.

Luc*_*ton 26

在不使用递归的情况下将元组转换为数组,包括使用完美转发(对于仅移动类型有用):

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

template<int... Indices>
struct indices {
    using next = indices<Indices..., sizeof...(Indices)>;
};

template<int Size>
struct build_indices {
    using type = typename build_indices<Size - 1>::type::next;
};

template<>
struct build_indices<0> {
    using type = indices<>;
};

template<typename T>
using Bare = typename std::remove_cv<typename std::remove_reference<T>::type>::type;

template<typename Tuple>
constexpr
typename build_indices<std::tuple_size<Bare<Tuple>>::value>::type
make_indices()
{ return {}; }

template<typename Tuple, int... Indices>
std::array<
  typename std::tuple_element<0, Bare<Tuple>>::type,
    std::tuple_size<Bare<Tuple>>::value
>
to_array(Tuple&& tuple, indices<Indices...>)
{
    using std::get;
    return {{ get<Indices>(std::forward<Tuple>(tuple))... }};
}

template<typename Tuple>
auto to_array(Tuple&& tuple)
-> decltype( to_array(std::declval<Tuple>(), make_indices<Tuple>()) )
{
    return to_array(std::forward<Tuple>(tuple), make_indices<Tuple>());
}

int main() {
  std::tuple<double, double, double> tup(1.5, 2.5, 4.5);
  auto arr = to_array(tup);
  for (double x : arr)
    std::cout << x << " ";
  std::cout << std::endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 现在有一个`std :: make_index_sequence`可以让这项工作变得更容易一些.使用它可能值得更新这个答案. (3认同)
  • +1索引数组正是我正在寻找的东西 - 对于`std :: tuple`来说是一种"为每个"框架.我提出了几个你的答案的编辑(我用`g ++ - 4.7 -std = c ++ 11`编译时修复了一些编译错误,并添加了一个`main`).非常感谢你的回答. (2认同)

Jon*_*ely 9

你可以非递归地做:

#include <array>
#include <tuple>
#include <redi/index_tuple.h>  // see below

template<typename T, typename... U>
  using Array = std::array<T, 1+sizeof...(U)>;

template<typename T, typename... U, unsigned... I>
  inline Array<T, U...>
  tuple_to_array2(const std::tuple<T, U...>& t, redi::index_tuple<I...>)
  {
    return Array<T, U...>{ std::get<I>(t)... };
  }

template<typename T, typename... U>
  inline Array<T, U...>
  tuple_to_array(const std::tuple<T, U...>& t)
  {
    using IndexTuple = typename redi::make_index_tuple<1+sizeof...(U)>::type;
    return tuple_to_array2(t, IndexTuple());
  }
Run Code Online (Sandbox Code Playgroud)

有关我的index_tuple的实现,请参阅https://gitlab.com/redistd/redistd/blob/master/include/redi/index_tuple.h,这对于使用元组和类似的可变参数模板非常有用.类似的实用程序std::index_sequence在C++ 14中标准化(对于独立的C++ 11实现,请参见index_seq.h).


ild*_*arn 5

我会返回数组而不是通过引用填充它,这样auto可以用来使调用站更清洁:

template<typename First, typename... Rem>
std::array<First, 1+sizeof...(Rem)>
fill_array_from_tuple(const std::tuple<First, Rem...>& t) {
  std::array<First, 1+sizeof...(Rem)> arr;
  ArrayFiller<First, decltype(t), 1+sizeof...(Rem)>::fill_array_from_tuple(t, arr);
  return arr;
}

// ...

std::tuple<double, double, double> tup(0.1, 0.2, 0.3);
auto arr = fill_array_from_tuple(tup);
Run Code Online (Sandbox Code Playgroud)

实际上,NRVO将消除大多数性能问题.


dav*_*igh 5

C ++ 17解决方案是一个简短的解决方案:

template<typename tuple_t>
constexpr auto get_array_from_tuple(tuple_t&& tuple)
{
    constexpr auto get_array = [](auto&& ... x){ return std::array{std::forward<decltype(x)>(x) ... }; };
    return std::apply(get_array, std::forward<tuple_t>(tuple));
}
Run Code Online (Sandbox Code Playgroud)

用作

auto tup = std::make_tuple(1.0,2.0,3.0);
auto arr = get_array_from_tuple(tup);
Run Code Online (Sandbox Code Playgroud)

编辑:忘记洒constexpr在任何地方:-)