Reputation: 8126
is there a simple way to create an std::array
from a parameter pack at compile time?
constexpr auto array = to_array<int>(1, 2, 3, 'a', 5.5f);
there are existing solutions:
std::to_array({...})
: sadly it only works when all argument types are equalwhat would be a clean way to implement this?
Upvotes: 1
Views: 1245
Reputation: 66200
What about simply
template <typename T, typename... Args>
constexpr std::array<T, sizeof...(Args)> to_array (Args && ... args)
{ return {{ std::forward<Args>(args)... }}; }
?
Or, maybe, if you want to add the static_cast
template <typename T, typename... Args>
constexpr std::array<T, sizeof...(Args)> to_array (Args && ... args)
{ return {{ static_cast<T>(std::forward<Args>(args))... }}; }
and using CTAD and auto
return placeholder, you can reduce a little the typewriting
template <typename T, typename... Args>
constexpr auto to_array (Args && ... args)
{ return std::array{ static_cast<T>(std::forward<Args>(args))... }; }
Upvotes: 4
Reputation: 8126
A straightforward solution is to expand the parameter pack while increasing an index to copy the values into the array:
template<typename T, typename... Args>
constexpr auto to_array(Args&&... args) {
std::array<T, sizeof...(Args)> result{};
unsigned ctr = 0u;
((result[ctr++] = static_cast<T>(args)), ...);
return result;
}
to show how this function would be callable with an std::tuple
one can unpack the tuple using an std::integer_sequence:
template<typename T, typename... Args>
constexpr auto to_array(std::tuple<Args...> tuple) {
auto unpack_tuple = [&]<class Tuple, size_t... Ints>(Tuple&& tuple, std::index_sequence<Ints...>) {
return to_array<T>(std::get<Ints>(tuple)...);
};
return unpack_tuple(tuple, std::make_index_sequence<sizeof...(Args)>{});
}
and using them:
int main() {
constexpr auto a = to_array<int>(std::tuple(5, 3, 'a', 1.0));
constexpr auto b = to_array<int>(5, 3, 'a', 1.0);
static_assert(a == b);
}
used headers:
#include <array>
#include <tuple>
#include <type_traits>
Upvotes: -1