2012-06-07 42 views
16

Làm cách nào để khởi tạo một số std::array từ một phạm vi (như được xác định bởi một cặp vòng lặp)?Khởi tạo std :: mảng với một dãy (cặp vòng lặp)

Something như thế này:

vector<T> v; 
... 
// I know v has exactly N elements (e.g. I just called v.resize(N)) 
// Now I want a initialized with those elements 
array<T, N> a(???); // what to put here? 

Tôi nghĩ array sẽ có một constructor lấy cặp vòng lặp, do đó tôi có thể làm array<T, N> a(v.begin(), v.end()), nhưng nó dường như không có nhà xây dựng ở tất cả!

Tôi biết tôi có thể copy véc tơ vào mảng, nhưng tôi muốn khởi tạo mảng bằng nội dung vectơ trực tiếp, mà không cần xây dựng mặc định trước tiên. Làm thế nào tôi có thể?

+0

Có lý do nào cho tùy chọn đó không? Hiệu suất sẽ gần như chính xác như nhau bởi vì hàm tạo mặc định (thường) chỉ phân bổ các cấu trúc cơ bản mà bạn cần. Sẽ không có phân bổ, sao chép hoặc giải phóng thêm. –

+1

@DavidSchwartz: Có lẽ tôi có một thành viên mảng const trong lớp của tôi và vì vậy tôi cần phải khởi tạo nó trong danh sách initializer chứ không phải là cơ quan constructor? – HighCommander4

+0

--- Chúng ta có thể giới hạn bản thân với các trình vòng lặp truy cập ngẫu nhiên không? Nếu vậy, tôi có một số loại giải pháp --- Nevermind, không có cách nào để có được * kích thước * tại thời gian biên dịch. –

Trả lời

17

Với lặp truy cập ngẫu nhiên, và giả định một kích thước nhất định tại thời gian biên dịch, bạn có thể sử dụng một pack of indices để làm như vậy:

template <std::size_t... Indices> 
struct indices { 
    using next = indices<Indices..., sizeof...(Indices)>; 
}; 
template <std::size_t N> 
struct build_indices { 
    using type = typename build_indices<N-1>::type::next; 
}; 
template <> 
struct build_indices<0> { 
    using type = indices<>; 
}; 
template <std::size_t N> 
using BuildIndices = typename build_indices<N>::type; 

template <typename Iterator> 
using ValueType = typename std::iterator_traits<Iterator>::value_type; 

// internal overload with indices tag 
template <std::size_t... I, typename RandomAccessIterator, 
      typename Array = std::array<ValueType<RandomAccessIterator>, sizeof...(I)>> 
Array make_array(RandomAccessIterator first, indices<I...>) { 
    return Array { { first[I]... } }; 
} 

// externally visible interface 
template <std::size_t N, typename RandomAccessIterator> 
std::array<ValueType<RandomAccessIterator>, N> 
make_array(RandomAccessIterator first, RandomAccessIterator last) { 
    // last is not relevant if we're assuming the size is N 
    // I'll assert it is correct anyway 
    assert(last - first == N); 
    return make_array(first, BuildIndices<N> {}); 
} 

// usage 
auto a = make_array<N>(v.begin(), v.end()); 

này giả định một trình biên dịch có khả năng eliding bản sao trung gian. Tôi nghĩ rằng giả định không phải là một căng lớn.

Thực tế, nó có thể được thực hiện với các trình lặp đầu vào, vì việc tính toán từng phần tử trong một danh sách-init-braced được sắp xếp trước khi tính toán phần tử tiếp theo (§8.5.4/4).

// internal overload with indices tag 
template <std::size_t... I, typename InputIterator, 
      typename Array = std::array<ValueType<InputIterator>, sizeof...(I)>> 
Array make_array(InputIterator first, indices<I...>) { 
    return Array { { (void(I), *first++)... } }; 
}  

Kể từ *first++ không có bất kỳ I trong nó, chúng ta cần một hình nộm I khiêu khích việc mở rộng gói. Toán tử dấu phẩy để giải cứu, với void() để tắt tiếng cảnh báo về việc thiếu hiệu ứng và cũng ngăn ngừa các dấu phẩy quá tải.

+0

+1. Tốt đẹp. (nhưng lần này tôi ghét cú pháp này: 'template >>>>' .Tôi có nghĩa là WTF.) – Nawaz

+0

Để làm rõ, 'BuildIndices' là mẫu' build_indices' trên trang được liên kết? Bạn có thể đưa nó vào đây để làm cho câu trả lời này độc lập không? – ecatmur

+0

Xem giải pháp của tôi sử dụng Boost. – Nawaz

4

Giống như bạn đã nhận thấy, std :: mảng không có hàm tạo nào cả (ngoại trừ trình biên dịch tạo ra hàm tạo mặc định).

Điều này đã được thực hiện với mục đích, vì vậy nó có thể được khởi tạo tĩnh giống như một mảng C. Nếu bạn muốn điền vào mảng mà không có bộ khởi tạo tĩnh, bạn sẽ phải sao chép dữ liệu của mình.

3

Bạn có thể sử dụng BOOST_PP_ENUM như:

include <boost/preprocessor/repetition/enum.hpp> 

#define INIT(z, i, v) v[i] 

std::vector<int> v; 

//fill v with at least 5 items 

std::array<int,5> a = { BOOST_PP_ENUM(5, INIT, v) }; //MAGIC 

Ở đây, dòng cuối cùng được mở rộng như:

std::array<int,5> a = {v[0], v[1], v[2], v[3], v[4]}; //EXPANDED LINE 

đó là những gì bạn muốn.

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