std::array
can be constructed (at compile time with newer C++ versions) with specific values, e.g.
std::array a{1, 4, 9};
however - it does not have a constructor, or a standard-library named constructor idiom, taking a single value and replicating it. i.e. we don't have:
std::array<int, 3> a{11};
// a == std::array<int, 3>{11, 11, 11};
How can we, therefore, construct an array given just the value to repeat?
Edit: I'm looking for a solution which would work even for element types which are not default constructible; so, a solution going through default-constructing the array, then filling it, is not what I'm after - despite the fact that this will work for the case of int
(like in the example).
We can write an appropriate named constructor idiom to achieve this. Then, your example definition would look like:
auto a = array_repeat<3>(11);
// a == std::array<int, 3>{11, 11, 11};
The implementation is a bit clunky, however, as we need to use the "indices trick" that takes a lot of boilerplate in C++11, so let's assume C++14:
namespace detail {
template<size_t, class T>
constexpr T&& identity(T&& x) { return std::forward<T>(x); }
template<class T, size_t... Indices>
constexpr auto array_repeat_impl(T&& x, std::index_sequence<Indices...>)
{
return std::experimental::make_array(identity<Indices>(x)...);
}
} // end detail
template<size_t N, class T>
constexpr auto array_repeat(T&& x)
{
return detail::array_repeat_impl(std::forward<T>(x), std::make_index_sequence<N>());
}
See this working on GodBolt.
If you can compile your code C++20, you can drop the dependency on make_array
and write:
namespace detail {
template<size_t, class T>
constexpr T&& identity(T&& x) { return std::forward<T>(x); }
template<class T, size_t... Indices>
constexpr auto array_repeat_impl(T&& x, std::index_sequence<Indices...>)
{
return std::array{identity<Indices>(x)...};
}
} // end detail
template<size_t N, class T>
constexpr auto array_repeat(T&& x)
{
return detail::array_repeat_impl(std::forward<T>(x), std::make_index_sequence<N>());
}
Notes:
tuple_repeat
, part of his tuple utilities for C++11.array_repeat_impl
.array_repeat()
function can take rvalue references and move from them, so it's ok to create a temporary in the argument, even if it's expensive.