es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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,>

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    La implementación de la función .at() utilizando la recursión se puede modificar de la siguiente manera:

    template <typename...>
    struct access_type;
    
    template <typename type,="" std::size_t...="" sizes="">
    struct access_type<><sizes...>, type>
    {
      template <typename array_type="">
      static constexpr type& at(array_type& array, const std::array<std::size_t, sizeof...(sizes)="">& position)
      {
        return at_impl(array, position, std::make_index_sequence<sizes...>{});
      }
    
    private:
      template <typename array_type,="" std::size_t...="" indices="">
      static constexpr type& at_impl(array_type& array, const std::array<std::size_t, sizeof...(sizes)="">& position, std::index_sequence<indices...>)
      {
        return (((void)indices), ..., array[position[indices]])[0];
      }
    };
    
    [[nodiscard]]
    constexpr reference at(const size_type& position)
    {
      return access_type<><sizes...>, value_type>::at(data_, position);
    }
    

    Explicación:

    • Definimos una estructura access_type que toma como parámetros un std::index_sequence y un paquete type. 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ámetro type será el tipo del elemento en el nivel hoja de la matriz multidimensional.
    • Especializamos la estructura access_type para std::index_sequence<sizes...> y value_type en nuestro caso específico.
    • Definimos una función miembro estática at que toma una referencia a un array de dimensiones arbitrarias, un std::array que contiene la posición del elemento al que queremos acceder, y devuelve una referencia al elemento.
    • En la función at, llamamos a una función auxiliar at_impl pasándole el array, la posición y un std::index_sequence creado a partir del paquete de parámetros sizes. 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.
    • En la función 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…>

Comments are closed.