Cela peut être fait, mais il faut quelques étapes pour le faire proprement. Tout d'abord, écrivez un template class
qui représente une plage de valeurs contiguës. Ensuite, transférez une template
version qui connaît la taille array
de la Impl
version qui prend cette plage contiguë.
Enfin, implémentez la contig_range
version. 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 .cpp
dossier:
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 set
cela supposera que les set
données sont contiguës, ce qui est faux, et fera un comportement indéfini partout. Les deux seuls std
conteneurs sur lesquels cela est garanti de fonctionner sont vector
et array
(et les tableaux de style C, en l'occurrence!). deque
bien que l'accès aléatoire ne soit pas contigu (dangereusement, il est contigu par petits morceaux!), list
n'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::vector
et 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
.