Questo può essere fatto, ma sono necessari alcuni passaggi per farlo in modo pulito. Innanzitutto, scrivi a template class
che rappresenta un intervallo di valori contigui. Quindi inoltra una template
versione che sa quanto è grande array
il fileImpl
versione che prende questo intervallo contiguo.
Infine, implementa la contig_range
versione. Nota che for( int& x: range )
funziona per contig_range
, perché ho implementato begin()
e end()
e i puntatori sono iteratori.
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 );
}
(non testato, ma il design dovrebbe funzionare).
Quindi, nel tuo .cpp
file:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
Questo ha lo svantaggio che il codice che esegue il ciclo sul contenuto dell'array non sa (in fase di compilazione) quanto è grande l'array, il che potrebbe costare l'ottimizzazione. Ha il vantaggio che l'implementazione non deve essere nell'intestazione.
Fai attenzione alla costruzione esplicita di a contig_range
, poiché se lo passi a set
, presumerà che i set
dati siano contigui, il che è falso, e comporterà un comportamento indefinito ovunque. Gli unici due std
contenitori su cui è garantito il funzionamento sono vector
e array
(e gli array in stile C, guarda caso!). deque
nonostante sia l'accesso casuale non è contiguo (pericolosamente, è contiguo in piccoli pezzi!),list
non è nemmeno vicino, ei contenitori associativi (ordinati e non ordinati) sono ugualmente non contigui.
Quindi i tre costruttori che ho implementato dove std::array
,std::vector
e in stile C gli array, che copre in pratica le basi.
Anche l'implementazione []
è facile, e tra for()
e []
questo è la maggior parte di ciò che vuoi array
, non è vero?
std::vector
.