How to initialize std :: array <T, n> elegantly if T is not constructive by default?
How to initialize std::array<T, n> if T is not constructive by default ?
I know that you can initialize it like this:
T t{args}; std::array<T, 5> a{t, t, t, t, t}; But n for me there is a template parameter:
template<typename T, int N> void f(T value) { std::array<T, N> items = ??? } And even if it wasnβt a template, itβs pretty ugly to repeat the value manually if n too large.
Given N, you can create a sequence type called seq<0,1,2,3,...N-1> using a generator named genseq_t<> , and then do the following:
template<typename T, int N> void f(T value) { //genseq_t<N> is seq<0,1,...N-1> std::array<T, N> items = repeat(value, genseq_t<N>{}); } where repeat is defined as:
template<typename T, int...N> auto repeat(T value, seq<N...>) -> std::array<T, sizeof...(N)> { //unpack N, repeating `value` sizeof...(N) times //note that (X, value) evaluates to value return {(N, value)...}; } The rest is defined as:
template<int ... N> struct seq { using type = seq<N...>; static const std::size_t size = sizeof ... (N); template<int I> struct push_back : seq<N..., I> {}; }; template<int N> struct genseq : genseq<N-1>::type::template push_back<N-1> {}; template<> struct genseq<0> : seq<> {}; template<int N> using genseq_t = typename genseq<N>::type; Hope this helps.
Unfortunately, existing answers here do not work for non-copyable types. So I accepted @Nawaz's answer and changed it:
#include <utility> #include <array> template<typename T, size_t...Ix, typename... Args> std::array<T, sizeof...(Ix)> repeat(std::index_sequence<Ix...>, Args &&... args) { return {{((void)Ix, T(args...))...}}; } template<typename T, size_t N> class initialized_array: public std::array<T, N> { public: template<typename... Args> initialized_array(Args &&... args) : std::array<T, N>(repeat<T>(std::make_index_sequence<N>(), std::forward<Args>(args)...)) {} }; Note that this is a subclass of std::array , so you can easily write
class A { A(int, char) {} } ... class C { initialized_array<A, 5> data; ... C(): data(1, 'a') {} } No repetition of type and size. Of course, this method can also be implemented as an initialize_array function.
Below is your problem:
#if 1 // Not in C++11, but in C++1y (with a non linear better version) template <std::size_t ...> struct index_sequence {}; template <std::size_t I, std::size_t ...Is> struct make_index_sequence : make_index_sequence<I - 1, I - 1, Is...> {}; template <std::size_t ... Is> struct make_index_sequence<0, Is...> : index_sequence<Is...> {}; #endif namespace detail { template <typename T, std::size_t ... Is> constexpr std::array<T, sizeof...(Is)> create_array(T value, index_sequence<Is...>) { // cast Is to void to remove the warning: unused value return {{(static_cast<void>(Is), value)...}}; } } template <std::size_t N, typename T> constexpr std::array<T, N> create_array(const T& value) { return detail::create_array(value, make_index_sequence<N>()); } So check this out:
struct NoDefaultConstructible { constexpr NoDefaultConstructible(int i) : m_i(i) { } int m_i; }; int main() { constexpr auto ar1 = create_array<10>(NoDefaultConstructible(42)); constexpr std::array<NoDefaultConstructible, 10> ar2 = create_array<10>(NoDefaultConstructible(42)); return 0; }