Można to zrobić, ale wystarczy kilka kroków, aby zrobić to czysto. Najpierw napisz a, template class
który reprezentuje zakres ciągłych wartości. Następnie przekaż template
wersję, która wie, jak duży array
jest, do Impl
wersji, która przyjmuje ten ciągły zakres.
Na koniec zaimplementuj contig_range
wersję. Zauważ, że for( int& x: range )
działa w przypadku contig_range
, ponieważ zaimplementowałem begin()
i, end()
a wskaźniki to iteratory.
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) {}
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 );
}
(nie testowane, ale projekt powinien działać).
Następnie w swoim .cpp
pliku:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
Ma to tę wadę, że kod, który zapętla zawartość tablicy, nie wie (w czasie kompilacji), jak duża jest tablica, co może kosztować optymalizację. Ma tę zaletę, że implementacja nie musi znajdować się w nagłówku.
Uważaj na jawne konstruowanie a contig_range
, ponieważ jeśli przekażesz a set
, przyjmie on, że set
dane są ciągłe, co jest fałszywe i będzie wykonywać niezdefiniowane zachowanie w każdym miejscu. Jedyne dwa std
kontenery, na których to działa, to vector
i array
(oraz tablice w stylu C, jak to się dzieje!). deque
pomimo tego, że dostęp losowy nie jest ciągły (niebezpiecznie, jest ciągły w małych kawałkach!), list
nie jest nawet blisko, a asocjacyjne (uporządkowane i nieuporządkowane) kontenery są równie nieciągłe.
Więc trzy konstruktory, które zaimplementowałem gdzie std::array
, std::vector
i tablice w stylu C, które w zasadzie obejmują podstawy.
Wykonawcza []
jest łatwe, jak również i między for()
i []
to większość tego, co chcesz, by array
dla, prawda?
std::vector
.