Esto se puede hacer, pero se necesitan algunos pasos para hacerlo de manera limpia. Primero, escriba un template classque represente un rango de valores contiguos. Luego, reenvíe una templateversión que sepa qué tan grande arrayes a la Implversión que toma este rango contiguo.
Finalmente, implemente la contig_rangeversión. Tenga en cuenta que for( int& x: range )funciona para contig_range, porque implementé begin()y end()y los punteros son iteradores.
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 );
}
(no probado, pero el diseño debería funcionar).
Luego, en su .cpparchivo:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
Esto tiene la desventaja de que el código que recorre el contenido de la matriz no sabe (en el momento de la compilación) qué tan grande es la matriz, lo que podría costar la optimización. Tiene la ventaja de que la implementación no tiene que estar en el encabezado.
Tenga cuidado al construir explícitamente a contig_range, ya que si lo pasa a set, asumirá que los setdatos son contiguos, lo cual es falso, y realizarán un comportamiento indefinido en todas partes. Los únicos dos stdcontenedores en los que se garantiza que esto funcionará son vectory array(¡y las matrices de estilo C, como sucede!). dequea pesar de ser el acceso aleatorio no es contiguo (peligrosamente, es contiguo en pequeños fragmentos), listni siquiera está cerca, y los contenedores asociativos (ordenados y desordenados) son igualmente no contiguos.
Así que los tres constructores implementé donde std::array, std::vectory al estilo de C matrices, que cubre básicamente las bases.
Ejecución []es fácil también, y entre for()y []que es más de lo que quiere una arraypara, ¿verdad?
std::vector.