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

template 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?

Bueno, primero tienes que entender que tratar de 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. Arrays (no referencias a ellos) como parámetros no existen en C ++. Si le da a un parámetro un tipo de matriz, será un puntero en su lugar. Entonces, 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 generalmente ocurre con las plantillas de funciones. La siguiente plantilla

 template size_t array_size(const T (&)[n]) { return n; } 

Llamado con nuestro conjunto previamente definido 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 un tiempo [Editar: resulta que alguien ya tenía la misma idea aquí ] que puede determinar un valor en tiempo de comstackción. En lugar de devolver el valor directamente, le da a la plantilla un tipo de devolución que depende de n :

 template char (& array_size(const T (&)[n]) )[n]; 

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

 size_t size_of_a = sizeof(array_size(a)); 

Debido a que una matriz de caracteres que tienen n elementos tiene tamaño de n , también le dará la cantidad de elementos en la matriz dada. En tiempo de comstackción, puedes hacer

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

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

Piénselo de esta manera, supongamos que tiene muchas 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 personalizas el arraysize, obtienes:

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

El comstackdor intentará crear una instancia de una versión de array_size que coincida con el parámetro con el que lo llame. Entonces, si lo llamas con una matriz de 10 ints, creará una instancia de array_size con n = 10.

A continuación, simplemente personalice el tipo, para que pueda llamarlo con más que solo matrices en int:

 template  size_t array_size(const T (&)[n]) { return n; } 

Y tu estas listo.

Editar : una nota sobre el (&)

Se necesitan los paréntesis alrededor de & para diferenciar entre la matriz de referencias int (ilegal) y la referencia a una matriz de ints (lo que desea). Como la precedencia de [] es mayor que & , si tiene la statement:

 const int &a[1]; 

debido a la precedencia del operador, terminas con una matriz de un elemento de referencias const a int. Si quiere aplicar & primero, debe forzarlo con paréntesis:

 const int (&a)[1]; 

Ahora que tienes 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 soltar el nombre, pero mantener los paréntesis:

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

Nada le sucede 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 utilizar como un argumento de plantilla, pero eso es un detalle separado.

Una forma un poco extraña de obtener el resultado como const en tiempo de comstackción para aquellos de nosotros que no tienen “constexpr”:

 #include  namespace { template  struct helper { enum { value = V }; }; template auto get_size(T(&)[Size]) -> helper < Size > { return helper < Size >() ; } template struct get_value { enum { value = T::value }; }; } int main() { std::cout << get_value::value; }