2011-10-17 5 views
6

No entiendo por qué la matriz se descompone en un puntero en una función de plantilla.por qué la matriz decae a un puntero en una función de plantilla

Si observa el siguiente código: Cuando el parámetro está forzado a ser una referencia (función f1), no decae. En la otra función f decae. ¿Por qué el tipo de T en la función f no es const char (buff &) [3] sino más bien const char * (si lo entiendo correctamente)?

#include <iostream> 

template <class T> 
void f(T buff) { 
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;  //prints 4 
} 

template <class T> 
void f1(T& buff) { 
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;  //prints 3 
} 

int main(int argc, char *argv[]) { 
    const char buff[3] = {0,0,0}; 
    std::cout << "buff size:" << sizeof(buff) << std::endl;   //prints 3 
    f(buff); 
    f1(buff); 
    return 0; 
} 
+0

Si simplemente pasó un 'en t' a 'f', luego' T' sería 'int', no' int & '. Por lo tanto, debería preguntar algo como "¿Por qué el tipo de T en la función f no es' const char [3] 'sino más bien' const char * '?" (tenga en cuenta la falta de '&' en comparación con su respuesta) –

+0

... (continuación de mi último comentario). Lo más estúpido del lenguaje C/C++ es que si coloca 'const char [3]' en sus parámetros, el compilador lo reescribirá silenciosamente como 'const char *'. Esto no sucede con las variables locales, por ejemplo. Realmente creo que esto debería conducir a advertencias hoy en día (de los compiladores de C++ al menos) –

Respuesta

7

Porque las matrices no se pueden pasar por valor como un parámetro de función.
Cuando los pasa por valor, se descomponen en un puntero.

En esta función:

template <class T> 
void f(T buff) { 

T no puede ser char (&buff)[3] ya que esto es una referencia. El compilador habría intentado char (buff)[3] para pasar por valor, pero eso no está permitido. Entonces, para hacerlo funcionar, las matrices decaen a punteros.

Su segunda función funciona porque aquí la matriz se pasa por referencia:

template <class T> 
void f1(T& buff) { 

// Here T& => char (&buff)[3] 
+0

Creo que la razón por la que no se pueden pasar por valor se relaciona con la falta de copia/asignación. (Aunque no puedo entender por qué me falta todo esto) –

+0

@MooingDuck: en C++ la razón es que el comportamiento particular fue heredado de C. En C la razón sería diferente, por supuesto ... –

+1

@MooingDuck: Y por supuesto ese es uno de las cosas que hacen que 'std :: array <>' sea inmediatamente superior a los C-arrays sin formato. – ildjarn

1

Dado que las funciones no pueden tener matrices como argumentos. Sin embargo, pueden tener referencias de matriz.

1

La razón básicamente se reduce a la deducción de tipo al hacer coincidir las diferentes sobrecargas. Cuando llama al f, el compilador deduce el tipo que será const char[3] que luego se descompone en const char* porque eso es lo que hacen las matrices. Esto se hace de la misma manera que en f(1) el compilador deduce T para ser int y no int&.

En el caso de f1 porque el argumento se toma como referencia, el compilador vuelve a deducir que T es const char[3], pero toma una referencia al mismo.

Nada realmente sorprendente, sino más bien consistente si no fuera por la descomposición de matrices de punteros cuando se utiliza como argumentos de la función ...

0

En f1(), Tamaño 4 es el tamaño del puntero, que es de 4 bytes. porque en esta función tienes un puntero a la matriz.

En f1(), tiene esa matriz por referencia (u otro nombre), y es el tamaño real de la matriz.

4

Para citar de especificación, se dice

(14.8.2.1/2) Si P no es un tipo de referencia: - Si A es un tipo de matriz, el tipo de puntero producida por la matriz a -pointer estándar de conversión (4.2) se usa en lugar de A para deducción de tipo; de lo contrario

Así, en su caso, es claro que,

template <class T> 
void f1(T& buff) { 
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;  //prints 3 
} 

no decae en puntero.

5

Esto dice porque matrices no se pueden pasar por valor a una función. Para que funcione, la matriz decae en un puntero que luego pasa a la función por el valor.

En otras palabras, el paso de una matriz por valor es similar a inicializar una matriz con otra matriz, pero en C++ una matriz no puede ser inicializan con otra matriz:

char buff[3] = {0,0,0}; 
char x[3] = buff; //error 

Así que si aparece una matriz en el lado derecho de =, el lado de la mano izquierda tiene que ser o bien pointer o reference tipo:

char *y = buff; //ok - pointer 
char (&z)[3] = buff; //ok - reference 

Demostración: http://www.ideone.com/BlfSv

Es exactamente por la misma razón auto es inferida de manera diferente en cada caso a continuación (tenga en cuenta que auto viene con C++ 11):

auto a = buff; //a is a pointer - a is same as y (above) 
std::cout << sizeof(a) << std::endl; //sizeof(a) == sizeof(char*) 

auto & b = buff; //b is a reference to the array - b is same as z (above) 
std::cout << sizeof(b) << std::endl; //sizeof(b) == sizeof(char[3]) 

Salida:

4 //size of the pointer 
3 //size of the array of 3 chars 

Demostración: http://www.ideone.com/aXcF5

Cuestiones relacionadas