Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]

Opciones de compilación

§1  Sinopsis

La generación de instancias de plantillas por el compilador Borland C++ 5.5 es controlada por las opciones -Jgd y -Jgx. Cada especialización de una plantilla viene afectada por el valor que tenía la opción Jg cuando dicha especialización fue vista por primera vez por el compilador.

Para las funciones genéricas la opción se aplica a las funciones concretas (especializaciones). Para las clases genéricas la opción se aplica a todos los métodos y miembros estáticos de la clase-plantilla. En cualquier caso, esta opción se aplica solamente a las especialidades generadas automáticamente por el compilador y nunca a las generadas por el usuario.  Las opciones Jg también pueden servir para indicar al compilador que instancias serán definidas por el usuario, de forma que no sean generadas por la plantilla.

Veremos que existen dos opciones que dan lugar a dos posibles estrategias de uso:

§1.1  Opción -Jgd (Smart)   ON por defecto

Esta es una opción bastante simple para generar instancias de plantillas. Cuando está activada, el compilador genera definiciones públicas (globales) para todas las instancias de plantillas. Si la misma instancia es generada en más de un módulo, el enlazador automáticamente las refunde en una sola definición de forma que solo exista una copia de cada instancia.

En el caso de funciones genéricas, para que puedan generarse las instancias es necesario que el compilador conozca el cuerpo de la plantilla-función (su definición).  Cuando son clases genéricas, debe conocer el cuerpo de los métodos y las definiciones de los miembros estáticos.  Generalmente esta información se coloca en un fichero de cabecera.


§1.2  Opción
-Jgx  (Externa)   OFF por defecto

Con esta opción, el compilador genera referencias externas para todas las instancias de plantillas. En cuyo caso, todas las instancias que deban ser enlazadas deben tener una directiva de instanciación explícita en, al menos, algún otro módulo.

§2  Organización de los ficheros

Son posibles dos estrategias:

§2.1   Incluir la definición de la plantilla en un fichero de cabecera. Si se trata de una función genérica, también se incluirá en dicho fichero la definición (cuerpo) de la función. Si es una clase genérica, se incluirán las definiciones de las funciones-miembro y de las propiedades estáticas.  Utilizándose el valor por defecto de la opción (-Jg).

Si alguna especialización es definida por el usuario, sus declaraciones (por ejemplo los prototipos) deben ser incluidos en el mismo fichero de cabecera, pero precedidos de la opción #pragma option -Jgx.

Ejemplo:

A continuación se define un fichero de cabecera donde se declara y define una plantilla. Cuando este fichero es incluido en un fuente, puede usarse la plantilla sort sin preocuparse de como se generan las diversas instancias (excepto el sort de matrices de enteros, que es una instancia definida por el usuario y cuya definición debe ser proporcionada aparte.

// Fichero de cabecera

template<class T> void sort (T* array, int size) {
  // cuerpo de la plantilla
}
// Ordenación particular que se realiza con un código definido por el usuario
#pragma option -Jgx
extern void sort(int *array, int size);
// Restaurar la opción a su estado original
#pragma option -Jg


§2.2
   La otra posibilidad es compilar todos los fuentes del programa con la opción -Jgx (lo que genera referencias externas a las instancias que se generarán).  Para procurar definición a todas estas instancias, deberán añadirse uno o varios ficheros incluyendo los cuerpos de las plantillas, así como cualquier instancia definida manualmente por el usuario. También deberán listarse todas las especilizaciones necesarias en el resto del programa para facilitar la adecuada definición de símbolos públicos. El fichero, o ficheros, deben compilarse con la opción -Jgd.

Ejemplo de compilación separada:

Fichero de cabecera vector.h:

// vector.h
template <class elem, int size> class vector {
  elem * value;
  public:
  vector();
  elem& operator[ ] (int index) {
    return value[index];
  }
};

Fichero main.cpp

#include "vector.h"
/* Permitir que el compilador conozca que las siguientes especializaciones están definidas en alguna parte */
#pragma option -Jgx
// Usar dos intancias de la plantilla vector
vector<int, 100> int_100;
vector<char, 10> char_10;

int main( ) {                 // =====================
  return int_100[ 0 ] + char_10[ 0 ];
}

Fichero template.cpp.

#include <string.h>
#include "vector.h"
// Definir una plantilla.
template <class elem, int size> vector <elem, size> :: vector() {
  value = new elem[size];
  memset(value, 0, size * sizeof(elem) );
}
// Generar las instancias necesarias.
#pragma option -Jgd
typedef vector<int, 100> fake_int_100;
typedef vector<char, 10> fake_char_10;