Це можна зробити, але для цього потрібно зробити кілька кроків. Спочатку напишіть a, template classщо представляє діапазон суміжних значень. Потім перешліть templateверсію, яка знає, наскільки велика arrayвона дляImpl версії, яка займає цей суміжний діапазон.
Нарешті, впровадити contig_rangeверсію. Зверніть увагу, що for( int& x: range )працює для contig_range, тому що я реалізував begin()і, end()а покажчики є ітераторами.
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 );
}
(не перевірено, але дизайн повинен працювати).
Потім у вашому .cppфайлі:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
Це має мінус, що код, який циклічно переглядає вміст масиву, не знає (під час компіляції), наскільки великий масив, що може коштувати оптимізації. Ця перевага полягає в тому, що реалізація не повинна бути в заголовку.
Будьте обережні при явному побудуванні a contig_range, оскільки, якщо ви його передасте, a setвін буде вважати, що setдані є суміжними, що є хибним, і виконуватиме невизначену поведінку всюди. Єдиними двома stdконтейнерами, над якими це гарантовано працювати, є vectorі array(і масиви у стилі С, як це трапляється!). dequeнезважаючи на те, що довільний доступ не є суміжним (небезпечно, він суміжний невеликими шматками!), listнавіть не близько, а асоціативні (упорядковані та невпорядковані) контейнери однаково несуміжні.
Отже, три конструктори, які я реалізував, де std::array, std::vectorі масиви у стилі С, які в основному охоплюють основи.
Реалізація []також проста, і між цим for()і []є більшість того, що вам потрібно array, чи не так?
std::vector.