Expansión variádica para acceder a std::array multidimensional.
Supongamos la siguiente estructura de matriz multidimensional:
template <typename type,="" std::size_t...="" sizes="">
struct multi_array
{
using storage_type = typename storage_type<type, sizes...="">::type;
using value_type = type;
using size_type = std::array<std::size_t ,="" sizeof...(sizes)="">;
using difference_type = std::array<std::ptrdiff_t, sizeof...(sizes)="">;
using reference = value_type&;
using const_reference = const value_type&;
// ...
storage_type data {};
size_type sizes {sizes...};
};
// Ejemplo de uso:
// multi_array<float, 3,="" 4,="" 5=""> three_dimensional_float_array;
// storage_type será std::array<><><float, 5="">, 4>, 3>
// size_type será std::array<std::size_t, 3="">
Donde:
// Ayudantes para crear un std::array<std::array<...>> a partir de una expansión del paquete.
template <typename type,="" std::size_t...="" sizes="">
struct storage_type;
template <typename _type,="" std::size_t="" size,="" std::size_t...="" sizes="">
struct storage_type<type, size,="" sizes...="">
{
using type = std::array<typename></typename><type, sizes...="">::type, size>;
};
template <typename _type="">
struct storage_type<type>
{
using type = _type;
};
Estoy intentando implementar la función `.at()`:
```cpp
[[nodiscard]]
constexpr reference at (const size_type& position)
{
// Esto debería ser:
// data_[position[0]][position[1]][position[2]]...;
}
</code></pre>
Las expresiones plegables no funcionan en este caso, por lo que se necesita una solución recursiva.
Creo que esta es la forma, pero no logro encontrar la respuesta correcta:
```cpp
[[nodiscard]]
constexpr reference at(const size_type& position)
{
return access_type<value_type, sizeof...(sizes)="">::at(data, position);
}
template
struct access_type
{
template
auto at (const array_type& array, const std::array<std::size_t, size="">& position)
{
if constexpr (index == 0)
return &array;
if constexpr (index + 1 != size)
{
return access_type<type, size,="" index="" +="" 1="">::at(array, position);
}
}
};
```</type,></std::size_t,>
</value_type,></type,></type,></std::array<...></std::size_t,></float,></float,></std::ptrdiff_t,></type,>
davy.ai
La implementación de la función
.at()
utilizando la recursión se puede modificar de la siguiente manera:Explicación:
access_type
que toma como parámetros unstd::index_sequence
y un paquetetype
. Esto nos permite pasar los tamaños de las dimensiones como argumentos en tiempo de compilación a las funciones recursivas que recorrerán la matriz multidimensional. El parámetrotype
será el tipo del elemento en el nivel hoja de la matriz multidimensional.access_type
parastd::index_sequence<sizes...>
yvalue_type
en nuestro caso específico.at
que toma una referencia a un array de dimensiones arbitrarias, unstd::array
que contiene la posición del elemento al que queremos acceder, y devuelve una referencia al elemento.at
, llamamos a una función auxiliarat_impl
pasándole el array, la posición y unstd::index_sequence
creado a partir del paquete de parámetrossizes
. Esto nos permite expandir la posición y los tamaños de las dimensiones en un paquete de parámetros de índices que se pueden utilizar para recorrer los elementos del array.at_impl
, utilizamos la expresión de despliegue(void)indices, ..., array[position[indices]]
para acceder al elemento en la posición dada. El operador coma evalúa sus operandos de izquierda a derecha, descarta el resultado de todas las expresiones excepto la más a la derecha (en este caso,array[position[indices]]
), y devuelve el resultado de la expresión más a la derecha ([0]
se usa aquí para convertir el elemento del array en una referencia).En general, esta implementación utiliza
std::index_sequence
, expresiones de despliegue y plantillas variadicas para lograr una solución compacta y eficiente para acceder a arrays multidimensionales.</sizes…></sizes…></indices…></std::size_t,></sizes…></std::size_t,></sizes…></typename…>