2012-06-28 32 views
5

Me preguntaba cuando creo una instancia de una plantilla de clase especificando el parámetro de tipo de plantilla.
1) ¿por qué no se instala la función no llamada? .
2) ¿no se compilan hasta que intento usarlo?
3) ¿Cuál es la lógica detrás de este comportamiento?

¿Por qué no se crean instancias de los miembros de clase de plantilla no llamados?

Ejemplo

template <class T> 
class cat{ 
public: 

T a; 
void show(){ 
    cout << a[0]; 
} 
void hello(){ 
    cout << "hello() get called \n"; 
} 
}; 

int main(){ 
cat<int> ob1; // I know that show() did not get instatiated, otherwise I will get an error since a is an int 
ob1.hello(); 

} 
+0

Qué compilador usó? –

Respuesta

3

Si crearon una instancia de toda la clase, es posible que obtenga un código no válido.

No siempre quiere eso.

¿Por qué? Porque en C++, es difícil (y en algunos casos, por completo imposible, hasta donde yo sé) decir, "compila solo este código si X, Y y Z son verdaderos".

Por ejemplo, ¿cómo diría "solo el constructor de mi copia si el objeto incrustado se puede copiar"? Hasta donde yo sé, no puedes.

Así que simplemente hicieron que no se compilen a menos que realmente los llames.

+0

es solo para la plantilla de la clase o en cualquier clase en general, y si no uso una función en una plantilla de clase ¿significa esto que la instancia de esta plantilla de clase no contiene esta función en absoluto? – AlexDan

+1

@AlexDan: solo plantillas. Presumiblemente, para las clases regulares, ya sabes todo sobre ellos, así que no hay nada que evitar, simplemente no incluyas código que no compila. Sin embargo, para las plantillas, no tienes idea de para qué van a crear instancias, pero aún quieres la capacidad de escribir código normal - entonces el compilador ayuda te gusta este. – Mehrdad

+0

haciendo "gato ob1;" Im creando solo la variable miembro y no perteneciendo a las funciones miembro es un miembro del objeto ob1 todavía. Si esto es correcto, ¿el compilador deja algo de memoria dentro del objeto ob1 en caso de que llame a una función? y también cambia el tamaño ob1 antes y después de llamar a una nueva función? muchas gracias . – AlexDan

2

se genera ningún código para cat<int>::show() porque nunca se lo llama. Si lo llamaras, obtendrías un error de compilación. Las funciones de plantilla que nunca se llaman no existen.

Las plantillas son poco más que mecanismos de sustitución de pruebas. Esto los hace muy poderosos. Usted, como programador, puede querer crear un cat<int> sabiendo que nunca llamará al show() ni llamará a nada que no sea válido. El compilador te permite saber si lo hiciste, por lo que funciona bien.

Entonces, si su pregunta es "¿por qué funciona de esta manera", le preguntaría "¿por qué no?" Es una elección de diseño. Esta opción me permite usar un tipo de plantilla de forma segura y aún así beneficiarme de otras partes del código. ¿Cuál es el daño? También genera menos código, lo cual es algo bueno, ¿no?

+1

Estoy bastante seguro de que el OP ya sabe esto. La pregunta claramente dice "por qué". – Mehrdad

+0

@Mehrdad: Agregué un poco justo antes de ver tu comentario. Supongo que no entiendo; "por qué"? Por qué no? Es seguro y me permite hacer más como programador, entonces ¿por qué restringir artificialmente el uso de plantillas? –

+0

@Mehrdad: la respuesta a cualquier "¿Por qué?" La pregunta en el diseño del lenguaje es "Porque los diseñadores así lo decidieron". Deben tomarse decisiones difíciles en los diseños, y con frecuencia no hay una razón clara y sin ambigüedades por las que fueron en un sentido u otro. – abelenky

6

Las plantillas no son código, sino un patrón utilizado para crear el código real. La plantilla no está completa hasta que suministre los parámetros para que el código no se pueda hacer antes de tiempo. Si no llama a una función con un conjunto particular de parámetros de plantilla, el código nunca se genera.

+0

Acordado +1, directo y al grano. –

+1

No es 100% cierto, solo para instancias implícitas. En las instancias explícitas de las plantillas se generan todas las funciones (lo que significa que es una decisión de diseño no hacerlo siempre, y hace que la respuesta sea solo la mitad: repite el enunciado de preguntas sin proporcionar demasiada explicación) –

3

para embellecer un poco más: lo que normalmente se llama duck typing, y la conclusión es que le permite escribir "patrones de clase" de los cuales algunos funciones miembros podrán aplicar cuando se crea una instancia de un tipo de plantilla, otra los miembros pueden postularse cuando se crean instancias con un segundo tipo de plantilla, y al requerir solo los que usted realmente llama para compilar, puede escribir mucho menos código para operaciones que terminan siendo comunes.

Al no requerir la compilación de todas las funciones miembro, se obtienen todas las sutilezas de la comprobación de tipo estático de las funciones que realmente son compiladas.

Por ejemplo, imagina que tenía:

template <typename E> 
    class myContainer { 

     // Imagine that constructors, setup functions, etc. were here 

     void sort(); // this function might make sense only if E has an operator< defined 

     E max(); // compute the max element, again only makes sense with a operator< 

     E getElement(int i); // return the ith element 

     E transmogrify(); // perhaps this operation only makes sense on vectors 
    }; 

entonces usted tiene

// sort() and getElement() makes total sense on this, but not transmogrify() 
    myContainer<int> mci;   

    // sort and max might not be needed, but getElement() and transmogrify() might 
    myContainer<vector<double>> mcvd;   
+0

Bajé todas las respuestas y voté en contra éste. finalmente uno que no afirma que una función de miembro no-plantilla es una plantilla –

+0

@ JohannesSchaub-litb: si la función de miembro no-plantilla no es una plantilla. entonces ¿cómo es que no se instala hasta que lo uso? – AlexDan

+1

@alexdan esto se explica en la respuesta que voté –

Cuestiones relacionadas