2013-08-28 27 views
21

Làm cách nào để khởi tạo std::array<T, n>nếu T không được mặc định là cấu hình?Cách khởi tạo std :: array <T, n> một cách tao nhã nếu T không được cấu hình mặc định?

Tôi biết nó có thể khởi tạo nó như thế:

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

Nhưng n đối với tôi là mẫu tham số:

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

Và thậm chí nếu nó không phải là mẫu, nó khá xấu xí để lặp lại giá trị bằng tay nếu n quá lớn.

+0

Có, bạn có thể viết một hoặc hai chức năng để tạo chúng. – chris

+0

Trợ giúp 'điền() 'có được hỗ trợ không? – Arun

+0

@Arun, no. Nó có thể được gọi chỉ trên mảng đã được xây dựng. – RiaD

Trả lời

26

Với N, bạn có thể tạo một chuỗi kiểu gọi seq<0,1,2,3,...N-1> sử dụng một máy phát điện gọi là genseq_t<>, sau đó làm điều này:

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

nơi repeat được định nghĩa là:

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

Và phần còn lại là được định nghĩa là:

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

Hy vọng điều đó sẽ hữu ích.

+1

Cảm ơn bạn đã đăng bài này. Tôi biết tôi đã nhìn thấy một cái gì đó như thế này trước và tôi đã không hoàn thành kết thúc của tôi đã cố gắng giải pháp. – chris

+0

@chris: Đã đăng [một bản demo] (http://ideone.com/UFadRE). – Nawaz

+0

Tại sao 'valuelist' là một 'integ_constant' như một bên? – Yakk

2

Tiếp theo sẽ giải quyết vấn đề của bạn:

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

Vì vậy, kiểm tra 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

Đáng buồn là câu trả lời hiện có ở đây không có tác dụng với nhiều loại phi copyable. Vì vậy, tôi mất @Nawaz câu trả lời và sửa đổi nó:

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

Lưu ý rằng đây là một lớp con std::array để người ta có thể dễ dàng viết

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

... 

class C { 
    initialized_array<A, 5> data; 

    ... 

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

Nếu không lặp lại những loại và kích cỡ. Tất nhiên, cách này cũng có thể được thực hiện như một hàm initialize_array.

Các vấn đề liên quan