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

6 minutos de lectura
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?

¿Alguien puede explicar este codigo de plantilla que me da
Johannes Schaub – litb

Bueno, primero debe comprender que tratar de obtener un valor de una matriz puede brindarle 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 hacen referencia 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 las 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 funciones. 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 instanciará implícitamente 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. [Edit: turns out someone already had that same idea here] 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 devolución dependiendo de n:

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

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

size_t size_of_a = sizeof(array_size(a));

Porque una matriz de char teniendo n los elementos tienen 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 nunca se llama a la función, no es necesario definirla, por lo que no tiene un cuerpo. Espero poder aclarar un poco el asunto.

  • Gracias litb publiqué la misma pregunta hace unos minutos 🙂 lo siento por la duplicación.

    – Khaled Alshaya

    24 de julio de 2009 a las 19:41

  • Me alegro de que hayas encontrado respuestas. No te preocupes por el engaño, no podrías saberlo 🙂

    – Johannes Schaub – litb

    24 de julio de 2009 a las 19:42

  • La desventaja de la última variante que usa un tipo de devolución apropiado: no funcionará con Microsoft Visual Studio 6 (que es bastante pobre en plantillas y falla en este caso). Desafortunadamente, es un factor decisivo para algunas tiendas (como en la que trabajo, que tiene que ser compatible con MSVC6).

    – Frerich Raabe

    6 de mayo de 2011 a las 6:02

  • con C++11 constexpr, el ‘retorno n;’ ¡La función se convierte en una constante de tiempo de compilación! template <typename T, size_t n> constexpr size_t array_size(const T (&)[n]) { return n; }

    – leyendas2k

    12 de abril de 2012 a las 13:22


  • template char (& array_size(const T (&)[n]) )[n]; y llamando a sizeof(array_size(a)); ¿Esto devuelve el tamaño total de la matriz = N * tamaño de char en lugar de devolver N – número de elementos?

    usuario6952310

    10 oct 2017 a las 11:39


¿Alguien puede explicar este codigo de plantilla que me da
Eclipse

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, ¿a qué función se llama?

int a[2];
array_size(a);  

Ahora, si creas una plantilla para el tamaño de la matriz, obtienes:

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

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

A continuación, solo cree una plantilla del tipo, para que pueda llamarlo con más que solo matrices int:

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

Y tu estas listo.

Editar: Una nota sobre el (&)

Los paréntesis son necesarios alrededor del & para diferenciar entre una matriz de referencias int (ilegal) y una referencia a una matriz de int (lo que desea). Dado que la precedencia de [] es más alto que &si tiene la declaración:

const int &a[1];

debido a la precedencia del operador, termina con una matriz de un elemento de referencias constantes a int. si quieres el & aplicado primero, necesita forzar eso con paréntesis:

const int (&a)[1];  

Ahora tiene una referencia constante a una matriz de enteros de un elemento. En la lista de parámetros de la función, 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])

  • ¿Por qué necesita los paréntesis alrededor de & en la versión de plantilla de la función, pero no en los ejemplos anteriores donde el tamaño de la matriz está codificado?

    – Alex

    23 de abril de 2009 a las 19:40

  • De hecho, necesitas los paréntesis en ambas situaciones.

    – eclipse

    23 de abril de 2009 a las 20:56

¿Alguien puede explicar este codigo de plantilla que me da
MSN

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 un argumento de plantilla, pero eso es un nit separado.

Una forma un poco extraña de obtener el resultado como const en 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;
}

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad