Điều này có thể được thực hiện, nhưng cần một vài bước để thực hiện sạch sẽ. Đầu tiên, hãy viết một template classđại diện cho một loạt các giá trị liền nhau. Sau đó, chuyển tiếp một templatephiên bản biết mức độ lớn arrayđến Implphiên bản có phạm vi tiếp giáp này.
Cuối cùng, thực hiện contig_rangephiên bản. Lưu ý rằng điều đó for( int& x: range )hoạt động contig_rangevì tôi đã triển khai begin()và end()và con trỏ là các trình vòng lặp.
template<typename T>
struct contig_range {
T* _begin, _end;
contig_range( T* b, T* e ):_begin(b), _end(e) {}
T const* begin() const { return _begin; }
T const* end() const { return _end; }
T* begin() { return _begin; }
T* end() { return _end; }
contig_range( contig_range const& ) = default;
contig_range( contig_range && ) = default;
contig_range():_begin(nullptr), _end(nullptr) {}
// maybe block `operator=`? contig_range follows reference semantics
// and there really isn't a run time safe `operator=` for reference semantics on
// a range when the RHS is of unknown width...
// I guess I could make it follow pointer semantics and rebase? Dunno
// this being tricky, I am tempted to =delete operator=
template<typename T, std::size_t N>
contig_range( std::array<T, N>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, std::size_t N>
contig_range( T(&arr)[N] ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, typename A>
contig_range( std::vector<T, A>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
};
void mulArrayImpl( contig_range<int> arr, const int multiplier );
template<std::size_t N>
void mulArray( std::array<int, N>& arr, const int multiplier ) {
mulArrayImpl( contig_range<int>(arr), multiplier );
}
(không được thử nghiệm, nhưng thiết kế sẽ hoạt động).
Sau đó, trong .cpptệp của bạn :
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
Điều này có nhược điểm là mã lặp qua nội dung của mảng không biết (tại thời điểm biên dịch) mảng lớn như thế nào, điều này có thể tốn chi phí tối ưu hóa. Nó có lợi thế là việc triển khai không cần phải có trong tiêu đề.
Hãy cẩn thận về việc xây dựng một cách rõ ràng a contig_range, vì nếu bạn chuyển nó a, setnó sẽ cho rằng setdữ liệu là liền kề, điều này là sai và thực hiện hành vi không xác định ở khắp nơi. Hai vùng stdchứa duy nhất mà điều này được đảm bảo hoạt động là vectorvà array(và mảng kiểu C, khi nó xảy ra!). dequemặc dù là truy cập ngẫu nhiên không liền kề (nguy hiểm là nó tiếp giáp theo từng phần nhỏ!), listthậm chí không gần nhau và các vùng chứa kết hợp (có thứ tự và không có thứ tự) cũng không liền nhau.
Vì vậy, các nhà xây dựng ba tôi thực hiện ở đâu std::array, std::vectorvà C-style mảng, mà về cơ bản bao gồm các căn cứ.
Việc triển khai []cũng dễ dàng và giữa for()và []đó là hầu hết những gì bạn muốn array, phải không?
std::vector.