2011-11-01 17 views
22

El código siguiente devuelve el tamaño de una matriz de pila asignados:¿Qué significa este código C++?

template<typename T, int size> 
int siz(T (&) [size]) 
{ 
    return size; 
} 

pero no puedo hacerme a la sintaxis. Especialmente la parte T (&) [size] ...

+1

posible duplicado de [¿Por qué la "referencia a la matriz" se define de manera tan confusa en C++?] (Http://stackoverflow.com/questions/6456253/why-is-reference-to-array-defined-in- such-confusing-way-in-c) – sharptooth

+7

no es exactamente un duplicado –

+0

Es posible que desee utilizar una plantilla de alias y escribir 'alias &' que puede ser más fácil de leer. –

Respuesta

24

pero no puedo hacerme a la sintaxis. Especialmente la parte T (&) [size] ...

Esa parte es una referencia a una matriz. Está el "right-left rule" para descifrar cualquier declaración de C y C++ .

Dado que las plantillas de función deducen tipos de argumento de plantilla de los argumentos de funciones proporcionados, lo que hace esta plantilla de funciones es deducir el tipo y el recuento de elementos de una matriz y devolver el recuento.

Las funciones no pueden aceptar tipos de matriz por valor, sino solo por puntero o referencia. La referencia se utiliza para evitar la conversión implícita de una matriz para el puntero a su primer elemento (aka, matriz de desintegración):

void foo(int*); 

int x[10]; 
int* p = x; // array decay 
foo(x);  // array decay again 

matriz de decaimiento destruye el tipo original de la matriz y por lo tanto el tamaño de la misma se pierde .

Tenga en cuenta que, dado que es una llamada a función en C++ 03, el valor de retorno no es una constante de tiempo de compilación (es decir, el valor de retorno no se puede usar como argumento de plantilla). En C++ 11 la función puede ser marcado con constexpr para devolver una constante de tiempo de compilación:

template<typename T, size_t size> 
constexpr size_t siz(T(&)[size]) { return size; } 

Para obtener el elemento de la matriz cuenta como una constante de tiempo de compilación en C++ 03 una forma ligeramente diferente puede ser utilizado:

template<class T, size_t size> 
char(&siz(T(&)[size]))[size]; // no definition required 

int main() 
{ 
    int x[10]; 
    cout << sizeof siz(x) << '\n'; 
    double y[sizeof siz(x)]; // use as a compile time constant 10 
} 

En lo anterior se declara una plantilla de función con el mismo argumento-reference-a un-array, pero con el tipo de valor de retorno de char(&)[size] (aquí es donde la "regla de izquierda-derecha" se puede apreciar) . Tenga en cuenta que la llamada a la función nunca ocurre en el tiempo de ejecución, por eso la definición de la plantilla de función siz es innecesaria. sizeof siz(x) es básicamente decir "cuál sería el tamaño del valor de retorno si siz(x) se llamaran".

la manera antigua C/C++ de conseguir el contador de elementos de una matriz como una constante de tiempo de compilación es:

#define SIZ(arr) (sizeof(arr)/sizeof(*(arr))) 
+0

son los parens alrededor del & necesario? –

+0

@JasonS: se requiere que los parens eviten parecer una serie de referencias a 'T' – Flexo

+0

ah, ok ... y' (T &) [size] 'tampoco? (Lo siento, no tengo un compilador de C funcionando) –

4

iT una función que se convierte en un nombre de tipo (plantillas se pueden utilizar con diferentes typenames) y un tamaño desde el exterior. Luego devuelve este tamaño.

Las funciones de pila a menudo usan size, que es un número entero que muestra el tamaño del tamaño de pila que solicita con esta función. El & prueba qué tamaño de la pila T significa.

7

T (&) [size] es una referencia a una matriz.Tiene que ser una referencia porque el programa siguiente no es legal:

#include <iostream> 

int sz(int *) { std::cout << "wtf?" << std::endl; return 0; } 


int sz(int [4]) { std::cout << "4" << std::endl; return 0; } 

int main() { 
    int test[4]; 
    sz(test); 
} 

Este programa no puede compilar con:

test.cc: In function ‘int sz(int*)’: 
test.cc:6:5: error: redefinition of ‘int sz(int*)’ 
test.cc:3:5: error: ‘int sz(int*)’ previously defined here 

porque int sz(int [4]) es idéntica a int sz(int *).

Los paréntesis son necesarios para desambiguar aquí porque T& [size] parece una matriz de referencias que, de lo contrario, es ilegal.

Normalmente, si el parámetro no era anónimo que iba a escribir:

template<typename T, int size> 
int sz(T (&arr) [size]) 

Para dar la matriz el nombre arr. En esta instancia, aunque todo el código de ejemplo que se preocupó fue el tamaño deducido y, por lo tanto, el argumento anónimo evita advertencias sobre argumentos no utilizados.

Cuestiones relacionadas