2010-04-25 13 views
5

En relación con el siguiente código, ¿cómo elige el compilador qué función de plantilla llamar? Si se omite la función const T &, siempre se llama a la función T &. Si se omite la función T &, siempre se llama a la función const T &. Si ambos están incluidos, los resultados son los siguientes.¿Cómo elige la compilación a qué función de plantilla llamar?

#include <iostream> 
#include <typeinfo> 

template <typename T> 
void function(const T &t) 
{ 
    std::cout << "function<" << typeid(T).name() << ">(const T&) called with t = " << t << std::endl; 
} 

template <typename T> 
void function(T &t) 
{ 
    std::cout << "function<" << typeid(T).name() << ">(T&) called with t = " << t << std::endl; 
} 

int main() 
{ 
    int i1 = 57; 
    const int i2 = -6; 

    int *pi1 = &i1; 
    int *const pi3 = &i1; 
    const int *pi2 = &i2; 
    const int *const pi4 = &i2; 

    function(pi1); ///just a normal pointer -> T& 
    function(pi2); ///cannot change what we point to -> T& 
    function(pi3); ///cannot change where we point -> const T& 
    function(pi4); ///cannot change everything -> const T& 

    return 0; 
} 

/* g++ output: 
function<Pi>(T&) called with t = 0x22cd24 
function<PKi>(T&) called with t = 0x22cd20 
function<Pi>(const T&) called with t = 0x22cd24 
function<PKi>(const T&) called with t = 0x22cd20 
*/ 

/* bcc32 output: 
function<int *>(T&) called with t = 0012FF50 
function<const int *>(T&) called with t = 0012FF4C 
function<int *>(const T&) called with t = 0012FF50 
function<const int *>(const T&) called with t = 0012FF4C 
*/ 

/* cl output: 
function<int *>(T&) called with t = 0012FF34 
function<int const *>(T&) called with t = 0012FF28 
function<int *>(const T&) called with t = 0012FF34 
function<int const *>(const T&) called with t = 0012FF28 
*/ 
+0

Un pequeño truco, cuando le toca estar usando g ++. '__PRETTY_FUNCTION__' proporciona una cadena bien formateada que describe su función, incluidos los tipos de parámetros de la plantilla [" int * "en lugar de" Pi "]. Encontré esto invaluable al aprender cómo funcionan las plantillas, ya que el comportamiento predeterminado para 'typeid (T) .name()' en g ++ es bastante críptico. Creo que '__FUNCSIG__' proporciona una funcionalidad similar en VS, pero no tengo acceso para verificarlo. –

Respuesta

3

Here es un breve resumen del proceso el compilador pasa. No cubre todo, pero te ayuda a comenzar.

En este caso, la decisión se toma igual que una función sin plantilla. Dados void f(int&) y void f(const int&), el primero se elegirá para las entradas regulares, y el segundo para las constantes. Los parámetros simplemente combinan mejor las entradas de esta manera: si proporciona una variable que puede modificar, llama a una función que puede modificarla; si proporciona una variable que no puede modificar, llama a una función que no puede modificarla.

En el código de ejemplo, pi2, siendo declarada como una const int *, es un puntero no constante a los datos constantes. Entonces, dentro de su función, puede cambiar t, pero no *t. Por el contrario, pi3 es un puntero constante a datos no constantes. Entonces puede cambiar *t pero no t.

Si ha cambiado su código levemente:

function(*pi1); 
function(*p12); 
function(*pi3); 
function(*pi4); 

En este caso, la primera y la tercera sería tanto resolver a la versión T&, porque *pi1 y *pi3 son ambos del tipo int& y por lo tanto se pueden modificar. *pi2 y *pi4 son ambos const int&, por lo que resuelven la sobrecarga const T&.

0

se trata de si la variable en sí misma es constante: la primera no es para nada constante. el segundo apunta a algo que es constante, pero podríamos cambiar donde apunta, el tercero y el cuarto tienen un puntero constante, lo que significa que la variable en sí es const, no podemos cambiar donde quiera que apunte.

typedef const int Cint; 
Cint * int1; 

obviamente puntero a constante int.

typedef int * Pint 
const Pint int2 

puntero obviamente constante para no constante int

Cuestiones relacionadas