Convert Std::Tuple to Std::Array C++11

Convert std::tuple to std::array C++11

Converting a tuple to an array without making use of recursion, including use of perfect-forwarding (useful for move-only types):

#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;
}

How to convert a homogenous tuple to an array at compile time?

I think this solves your problem in a somehow generic way:

namespace detail {

template <class Tuple>
struct make_array;

template <class V, template <V N> class C, V... Ns>
struct make_array<std::tuple<C<Ns>... >> {
static constexpr std::array value{Ns... };
};

template <class Tuple>
constexpr auto make_array_v = make_array<Tuple>::value;

}

It is basically a template with a std::tuple specialization for std::tuple of a given template argument with a list of values.

Here are possible usages (assuming Char is similar to your Int bur for char):

constexpr auto arr1 = detail::make_array_v<std::tuple<Int<42>, Int<38>, Int<57>>>;
static_assert(arr1 == std::array<std::size_t, 3>{42, 38, 57});

constexpr auto arr2 = detail::make_array_v<std::tuple<Char<'A'>, Char<'Z'>,
Char<'w'>, Char<'U'>>>;
static_assert(arr2 == std::array{'A', 'Z', 'w', 'U'});

The implementation is valid for C++17, and I think quite easy to convert for C++14 (you just have to specify the template arguments for value). The tests above require C++20 for the constexpr comparison operator for std::array.


Full godbolt.org code with your example: https://godbolt.org/z/jkiA9R

C++11 std::tuple to std::array conversion causes variadic template crash

It looks valid to me, and the finished version works fine with G++:

#include <redi/index_tuple.h>
template <typename T, typename... U, unsigned... N>
std::array<T, sizeof...(U)>
toArray2(std::tuple<U...>& t, redi::index_tuple<N...>) {
return std::array<T, sizeof...(U)>{{ std::get<N>(t)... }};
}

template <typename T, typename ...U>
std::array<T, sizeof...(U)>
toArray(std::tuple<U...> t) {
return toArray2<T>(t, redi::to_index_tuple<U...>{});
}

int main()
{
auto tup = std::make_tuple(1,2,3,4,5,6,7,8);
return toArray<int>(tup)[3] - 4;
}

How to construct a tuple from an array

As with all questions involving std::tuple, use index_sequence to give you a parameter pack to index the array with:

template <class... Formats, size_t N, size_t... Is>
std::tuple<Formats...> as_tuple(std::array<char*, N> const& arr,
std::index_sequence<Is...>)
{
return std::make_tuple(Formats{arr[Is]}...);
}

template <class... Formats, size_t N,
class = std::enable_if_t<(N == sizeof...(Formats))>>
std::tuple<Formats...> as_tuple(std::array<char*, N> const& arr)
{
return as_tuple<Formats...>(arr, std::make_index_sequence<N>{});
}

Which you would use as:

std::tuple<Format...> the_line = as_tuple<Format...>(toks);

Convert scalar + std::array + std::tuple into a big tuple

This seems to work:

template<typename T1, typename T2>
struct concat_tuples;

template<typename... T1, typename... T2>
struct concat_tuples<std::tuple<T1...>, std::tuple<T2...>>
{
using type = std::tuple<T1..., T2...>;
};

// n_tuple<int, 3>::type == std::tuple<int, int, int>
template<typename T, size_t n>
struct n_tuple;

template<typename T>
struct n_tuple<T, 0>
{
using type = std::tuple<>;
};

template<typename T, size_t n>
struct n_tuple
{
using type = typename concat_tuples<
typename n_tuple<T, n-1>::type,
std::tuple<T>
>::type;
};

template <class Scalar, class Array, class Tuple>
struct Test;

template <class Scalar, typename T, size_t n, typename... Ts>
struct Test<Scalar, std::array<T, n>, std::tuple<Ts...>>
{
using type = typename concat_tuples<
typename concat_tuples<
std::tuple<Scalar>,
typename n_tuple<T, n>::type
>::type,
std::tuple<Ts...>
>::type;
};

Live demo here.

What is a one-line expression for constructing a C++ tuple with an array (C or std::array) element?

You need an extra pair of brackets {} around the array:

std::tuple<std::array<std::array<int, 2>, 2>, int> v({{{0, 1}, {2, 3}}}, 1);
^ ^

This is because std::array is initialized using aggregate-initialization. It works with std::vector because there is std::vector<std::initializer_list<T> constructor (std::array does not have any constructors).



Related Topics



Leave a reply



Submit