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
C++ For-Loop - Size_Type VS. Size_T
Does the Gotw #101 "Solution" Actually Solve Anything
Is It Reasonable to Use Std::Basic_String<T> as a Contiguous Buffer When Targeting C++03
C++ Qt Signal and Slot Not Firing
Floating Point Comparison Revisited
Reorder Vector Using a Vector of Indices
What Makes a Static Variable Initialize Only Once
Placement New and Assignment of Class with Const Member
Trouble with Inheritance of Operator= in C++
Unsequenced Value Computations (A.K.A Sequence Points)
Why Doesn't My Template Accept an Initializer List
How to Make an Expandable/Collapsable Section Widget in Qt
In What Ways Do C++ Exceptions Slow Down Code When There Are No Exceptions Thown