2013-08-28 7 views
21

Tがデフォルトのコンストラクタブルでない場合、std::array<T, n>を初期化するにはTがデフォルトコンストラクタブルでない場合、std :: array <T, n>をエレガントに初期化するには?

私はそのようにそれを初期化することが可能です知っている:私のために

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

しかしnは、テンプレートパラメータである:

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

そしてそれは、テンプレートではなかった場合でも、それは繰り返してはかなり醜いですnが大きすぎる場合は手作業による値。

+0

はい、関数を1つまたは2つ作成して生成できます。 – chris

+0

'fill() 'は役に立ちますか? – Arun

+0

@Arun、no。すでに構築された配列に対してのみ呼び出されることがあります。 – RiaD

答えて

26

Nは、あなたがこれを行うには、genseq_t<>と呼ばれる発電機を使用してseq<0,1,2,3,...N-1>と呼ばれるシーケンス型を生成することができ考える:

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

、残りは次のとおりです。repeatは次のように定義されて

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

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

希望があれば

+1

これを投稿していただきありがとうございます。これまで私がこのようなことをしていたことは分かっていました。 – chris

+0

@chris:[デモ](http://ideone.com/UFadRE)も公開しました。 – Nawaz

+0

なぜvaluelistは控除として「integral_constant」ですか? – Yakk

2

あなたの問題を解決する次のとおりです。

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

だから、それをテスト:

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

悲しいことに、ここで既存の答えは非コピー可能なタイプには対応していません。だから私は@Nawazの答えを取って、それを修正:

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

注1は、簡単に種類やサイズを繰り返すことなく

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

... 

class C { 
    initialized_array<A, 5> data; 

    ... 

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

を書くことができるように、これはstd::arrayサブクラスであること。もちろん、この方法は関数initialize_arrayとして実装することもできます。

関連する問題