2010-03-05 5 views
19

En el siguiente códigoargumentos mágicos en plantillas de función

#include<iostream> 

template<typename T,size_t N> 
void cal_size(T (&a)[N]) 
{ 
    std::cout<<"size of array is: "<<N<<std::endl; 
} 

int main() 
{ 
    int a[]={1,2,3,4,5,6}; 
    int b[]={1}; 

    cal_size(a); 
    cal_size(b); 
} 

Como era de esperar el tamaño tanto de las matrices que se imprime. ¿Pero cómo N se inicializa automáticamente al valor correcto del tamaño de la matriz (las matrices se pasan por referencia)? ¿Cómo está funcionando el código anterior?

+2

Ver http: // stackoverflow.com/questions/437150/can-someone-explain-this-template-code-that-gives-me-the-size-of-a-array (¿dupe?) –

+3

"deducción de argumento de plantilla" es lo que estoy buscando. Gracias Andrey :) –

Respuesta

31

N no quede "inicializar" a cualquier cosa. No es una variable. No es un objeto N es una constante en tiempo de compilación. N solo existe durante la compilación. El valor de N así como el T real se determina mediante el proceso deducción del argumento de la plantilla. Ambos T y N se deducen del tipo real del argumento que pasa a su función de plantilla.

En la primera llamada el tipo de argumento es int[6], por lo que el compilador deduce que T == int y N == 6, genera una función separada para eso y lo llama. Vamos a nombrar que cal_size_int_6

void cal_size_int_6(int (&a)[6]) 
{ 
    std::cout << "size of array is: " << 6 << std::endl; 
} 

Tenga en cuenta que no hay ninguna T y N en esta función más. Ambos fueron reemplazados por sus valores reales deducidos en tiempo de compilación.

En la primera llamada el tipo de argumento es int[1], por lo que el compilador deduce que T == int y N == 1, genera una función separada para eso también y lo llama. Vamos a nombrar que cal_size_int_1

void cal_size_int_1(int (&a)[1]) 
{ 
    std::cout << "size of array is: " << 1 << std::endl; 
} 

mismo aquí.

Su main se traduce esencialmente en

int main() 
{ 
    int a[]={1,2,3,4,5,6}; 
    int b[]={1}; 

    cal_size_int_6(a); 
    cal_size_int_1(b); 
} 

En otras palabras, su plantilla cal_size da a luz a dos funciones diferentes (los llamados especializaciones de la plantilla original), cada uno con diferentes valores de N (y T) codificados en el cuerpo. Así es como funcionan las plantillas en C++.

+3

De hecho, comeau acepta esto: 'template void f (int (&)[S]); int main() {int a [UCHAR_MAX + 1]; f (a);}'. Lo curioso es , ni siquiera estoy seguro de lo que dice el Estándar sobre este fragmento (parece decir que la llamada tiene éxito, pero no especifica qué valor tiene 'S' en el cuerpo de la función). En cualquier caso, comeau le da el tipo a' S' "char sin signo", pero le da el valor real (fuera de su rango) dentro del cuerpo de la función. –

1

cuando declara int a [] = {1,2,3} es lo mismo que (o se volverá a escribir como) int a [3] = {1,2,3} ya que la función de plantilla está recibiendo argumento en forma de T a [N], entonces N tendrá valor de 3.

8

funciona porque el tipo de a es "matriz de longitud 6 de int" y el tipo de b es "matriz de longitud 1 de int ". El compilador lo sabe, por lo que puede llamar a la función correcta. En particular, la primera llamada llama a la instancia de plantilla cal_size<6>() y la segunda llamada a cal_size<1>(), ya que esas son las únicas instancias de plantilla que coinciden con sus respectivos argumentos.

Si intentó llamar a una instancia de plantilla explícita, solo funcionaría si tuviera el tamaño correcto, de lo contrario los argumentos no coincidirían. Considere lo siguiente:

cal_size(a); // ok, compiler figures out implicitly that N=6 
cal_size<int, 6>(a); // also ok, same result as above 
cal_size<int, 5>(a); // ERROR: a is not of type "array of length 5 of int" 
Cuestiones relacionadas