Cela peut être fait, mais il faut quelques étapes pour le faire proprement. Tout d'abord, écrivez un template classqui représente une plage de valeurs contiguës. Ensuite, transférez une templateversion qui connaît la taille arrayde la Implversion qui prend cette plage contiguë.
Enfin, implémentez la contig_rangeversion. Notez que cela for( int& x: range )fonctionne pour contig_range, car j'ai implémenté begin()et end()et les pointeurs sont des itérateurs.
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 testé, mais la conception devrait fonctionner).
Ensuite, dans votre .cppdossier:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
Cela a l'inconvénient que le code qui boucle sur le contenu du tableau ne sait pas (au moment de la compilation) la taille du tableau, ce qui pourrait coûter l'optimisation. Il présente l'avantage que l'implémentation ne doit pas nécessairement figurer dans l'en-tête.
Faites attention à ne pas construire explicitement a contig_range, comme si vous le transmettez a setcela supposera que les setdonnées sont contiguës, ce qui est faux, et fera un comportement indéfini partout. Les deux seuls stdconteneurs sur lesquels cela est garanti de fonctionner sont vectoret array(et les tableaux de style C, en l'occurrence!). dequebien que l'accès aléatoire ne soit pas contigu (dangereusement, il est contigu par petits morceaux!), listn'est même pas proche, et les conteneurs associatifs (ordonnés et non ordonnés) sont également non contigus.
Donc, les trois constructeurs que j'ai implémentés où std::array, std::vectoret les tableaux de style C, qui couvrent essentiellement les bases.
La mise en œuvre []est également facile, et entre for()et []c'est ce que vous recherchez array, n'est-ce pas?
std::vector.