¿Alguien puede explicar este código de plantilla que me da el tamaño de una matriz? [duplicar]

StackOverflow https://stackoverflow.com/questions/437150

  •  22-07-2019
  •  | 
  •  

Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         
template<typename T, size_t n>
size_t array_size(const T (&)[n])
{
    return n;
}

La parte que no entiendo son los parámetros para esta función de plantilla. ¿Qué sucede con la matriz cuando la paso por allí que da n como el número de elementos en la matriz?

¿Fue útil?

Solución

Bueno, primero debes entender que intentar obtener un valor de una matriz puede darte un puntero a su primer elemento:

int a[] = {1, 2, 3};
int *ap = a; // a pointer, size is lost
int (&ar)[3] = a; // a reference to the array, size is not lost

Las referencias se refieren a objetos que usan su tipo exacto o su tipo de clase base. La clave es que la plantilla toma matrices por referencia. Las matrices (no referencias a ellas) como parámetros no existen en C ++. Si le da a un parámetro un tipo de matriz, será un puntero en su lugar. Por lo tanto, es necesario usar una referencia cuando queremos saber el tamaño de la matriz pasada. El tamaño y el tipo de elemento se deducen automáticamente, como suele ser el caso de las plantillas de función. La siguiente plantilla

template<typename T, size_t n>
size_t array_size(const T (&)[n]) {
    return n;
}

Llamado con nuestra matriz previamente definida a , creará una instancia implícita de la siguiente función:

size_t array_size(const int (&)[3]) {
    return 3;
}

Que se puede usar así:

size_t size_of_a = array_size(a);

Hay una variación que inventé hace algún tiempo [Editar: resulta que alguien ya tenía esa misma idea aquí ] que puede determinar un valor en tiempo de compilación. En lugar de devolver el valor directamente, le da a la plantilla un tipo de retorno dependiendo de n :

template<typename T, size_t n>
char (& array_size(const T (&)[n]) )[n];

Usted dice que si la matriz tiene elementos n , el tipo de retorno es una referencia a una matriz que tiene un tamaño n y un tipo de elemento char . Ahora, puede obtener un tamaño determinado en tiempo de compilación de la matriz aprobada:

size_t size_of_a = sizeof(array_size(a));

Debido a que una matriz de char que tiene elementos n tiene un tamaño de n , eso también le dará la cantidad de elementos en la matriz dada. En tiempo de compilación, para que pueda hacer

int havingSameSize[sizeof(array_size(a))];

Debido a que la función nunca se llama realmente, no necesita ser definida, por lo que no tiene cuerpo. Espero poder aclarar el asunto un poco.

Otros consejos

Piénselo de esta manera, suponga que tiene un montón de funciones:

// Note that you don't need to name the array, since you don't
// actually reference the parameter at all.
size_t array_size(const int (&)[1])
{
    return 1;
}

size_t array_size(const int (&)[2])
{
    return 2;
}

size_t array_size(const int (&)[3])
{
    return 3;
}
// etc...

Ahora, cuando llamas a esto, ¿qué función se llama?

int a[2];
array_size(a);  

Ahora, si crea la matriz de tamaño de matriz, obtendrá:

template <int n>
size_t array_size(const int (&)[n])
{
    return n;
}

El compilador intentará crear una instancia de array_size que coincida con cualquier parámetro con el que lo llame. Entonces, si lo llama con una matriz de 10 ints, instanciará array_size con n = 10.

A continuación, simplemente modifique el tipo, para que pueda llamarlo con más que solo arrays int:

template <typename T, int n>
size_t array_size(const T (&)[n])
{
    return n;
}

Y ya terminaste.

Editar : una nota sobre el (&)

Los paréntesis son necesarios alrededor del & amp; para diferenciar entre la matriz de referencias int (ilegal) y la referencia a la matriz de entradas (lo que desea). Dado que la precedencia de [] es mayor que & amp; , si tiene la declaración:

const int &a[1];

debido a la precedencia del operador, terminas con una matriz de un elemento de referencias constantes a int. Si desea que el & amp; se aplique primero, debe forzarlo con paréntesis:

const int (&a)[1];  

Ahora tiene una referencia constante a una matriz de elementos de un elemento. En la lista de parámetros de funciones, no necesita especificar el nombre de un parámetro si no lo usa, por lo que puede quitar el nombre, pero mantener los paréntesis:

size_t array_size(const int (&)[1])

No le pasa nada a la matriz. Es un parámetro no utilizado que se utiliza para resolver la firma de la función de plantilla.

Tampoco se puede usar como argumento de plantilla, pero es un nit separado.

Una pequeña forma extraña de obtener el resultado como constante de tiempo de compilación para aquellos de nosotros que no tenemos "constexpr":

#include <iostream>

namespace
{

    template <size_t V>
    struct helper
    {
        enum
        {
            value = V
        };
    };


    template<typename T, size_t Size>
    auto get_size(T(&)[Size]) -> helper < Size >
    {
        return helper < Size >() ;
    }

    template<typename T>
    struct get_value
    {
        enum
        {
            value = T::value
        };
    };

}

int main()
{
    std::cout << get_value<decltype(get_size("Foo bar baz"))>::value;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top