2013-08-28 9 views
21

Come inizializzare std::array<T, n>se T non è predefinito costruibile?Come inizializzare std :: array <T, n> con eleganza se T non è il default costruibile?

so che è possibile inizializzare in quel modo:

T t{args}; 
std::array<T, 5> a{t, t, t, t, t}; 

Ma n per me è parametro di modello:

template<typename T, int N> 
void f(T value) 
{ 
    std::array<T, N> items = ??? 
} 

E anche se non era modello, è abbastanza brutto a ripetere valore a mano se n è troppo grande.

+0

Sì, è possibile scrivere una funzione o due per generarli. – chris

+0

L'aiuto 'fill() '? – Arun

+0

@Arun, no. Può essere chiamato solo su array già costruiti. – RiaD

risposta

26

Dato N, si potrebbe generare una sequenza-tipo chiamato seq<0,1,2,3,...N-1> utilizzando un generatore chiamato genseq_t<>, quindi fare questo:

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>{}); 
} 

dove repeat è definito come:

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)...}; 
} 

e il resto è definito come:

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; 

Online demo

Spero che questo aiuti.

+1

Grazie per aver postato questo. Sapevo di aver già visto qualcosa di simile prima e non avevo ancora finito la mia tentata soluzione. – chris

+0

@chris: pubblicato [una demo] (http://ideone.com/UFadRE) anche. – Nawaz

+0

Perchè 'valuelist' è un' integral_constant' come un lato? – Yakk

2

seguito risolverà il tuo problema:

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

Così testarlo:

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

Purtroppo le risposte esistenti qui non funzionano per i tipi non copiabile. Così ho preso @Nawaz risposta e modificato è:

#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)...)) {} 
}; 

Si noti che si tratta di un std::array sottoclasse in modo che si può facilmente scrivere

class A { 
    A(int, char) {} 
} 

... 

class C { 
    initialized_array<A, 5> data; 

    ... 

    C(): data(1, 'a') {} 
} 

Senza ripetere il tipo e la dimensione. Naturalmente, questo modo può essere implementato anche come funzione initialize_array.

Problemi correlati