Dies ist möglich, erfordert jedoch einige Schritte, um es sauber zu machen. Schreiben Sie zunächst a template class
, das einen Bereich zusammenhängender Werte darstellt. Leiten Sie dann eine template
Version, die weiß, wie groß die array
ist, an die Impl
Version weiter, die diesen zusammenhängenden Bereich einnimmt.
Implementieren Sie abschließend die contig_range
Version. Beachten Sie, dass dies for( int& x: range )
funktioniert contig_range
, da ich implementiert habe begin()
und end()
und Zeiger Iteratoren sind.
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 );
}
(nicht getestet, aber das Design sollte funktionieren).
Dann in Ihrer .cpp
Datei:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
Dies hat den Nachteil, dass der Code, der den Inhalt des Arrays durchläuft, (zur Kompilierungszeit) nicht weiß, wie groß das Array ist, was zu einer Kostenoptimierung führen kann. Dies hat den Vorteil, dass sich die Implementierung nicht im Header befinden muss.
Seien Sie vorsichtig beim expliziten Erstellen von a contig_range
, als ob Sie es übergeben würden. set
Es wird davon ausgegangen, dass die set
Daten zusammenhängend sind, was falsch ist, und überall undefiniertes Verhalten zeigen. Die einzigen zwei std
Container, an denen dies garantiert funktioniert, sind vector
und array
(und Arrays im C-Stil, wie es passiert!). deque
Obwohl der Direktzugriff nicht zusammenhängend ist (gefährlich, er ist in kleinen Stücken zusammenhängend!), list
ist er nicht einmal in der Nähe und die assoziativen (geordneten und ungeordneten) Container sind gleichermaßen nicht zusammenhängend.
Also die drei Konstruktoren, die ich wo implementiert habe std::array
, std::vector
und C-artige Arrays, die im Grunde die Basen abdecken.
Die Implementierung []
ist ebenfalls einfach, und dazwischen for()
und []
das ist das meiste, wofür Sie sich wünschen array
, nicht wahr?
std::vector
.