[C con Clase] Ayuda definición templates y structs

Steven Davidson srd4121 en njit.edu
Mar Jul 21 19:21:29 CEST 2009


Hola Jorge,

Jorge Vega Sanchez wrote:
> 

[CORTE]

> Buenas y gracias de antemano a todo aquel que se lea un poco este
> código que he puesto.
> TEngo dudas sobre las definición de los tipos de datos, creo que no 
> comprendo bien los define, template y los structs, porque me parece
> ver redundancias por todos lados.
> 

Muy bien. Veamos las dudas.

> DUDAS:
> 1ª Linea 24. No comprendo este template. No se supone que un template
> es para crear una estructura facilemnte repetible, tipo plantilla o
> algo así. No entiendo que hace un template justo antes de una
> definición de este 'struct'.
> 

Estás hablando de la siguiente definición:

template< typename T, bool INIT = true >
struct ThreadInitInvoker
{
   static void ThreadInit( T *obj )
   {
     obj->ThreadInit();
   }
};

Estamos definiendo una plantilla de una estructura. Esto significa que 
podemos definir múltiples estructuras con tan sólo cambiar los 
parámetros de la plantilla. Por ejemplo,

typedef ThreadInitInvoker<int> IntThreadInitInvoker;
typedef ThreadInitInvoker<IntThreadInitInvoker> TIIIntThreadInitInvoker;

y así sucesivamente.

Puedes consultar el capítulo 40 de nuestro curso de C++ yendo a: 
http://c.conclase.net/curso/index.php?cap=040 para el tema de las 
plantillas.

> 2ª Lineas 62 y 63. Definición de variables privadas dentro de una
> clase. Que significa '::' delante de la definición de las variables.
> 

Estamos hablando de esto:

template< ... >
class Tls
{
   ...
   static ::pthread_key_t tlsKey;
   static ::pthread_key_t initKey;
};

El símbolo :: es el operador de ámbito o mejor dicho el de acceso a un 
ámbito. Las sintaxis son:

<nombre_del_ámbito> :: <nombre_de_la_entidad>
:: <nombre_de_la_entidad>

Si no existe un nombre antes del operador del ámbito, entonces se 
considera el ámbito global.

En el código fuente, estamos usando la definición global del tipo 
'pthread_key_t'. En este caso, realmente no es necesario, porque no 
existe otra definición de este tipo en este ámbito de 'wlpdstm' ni 
tampoco en 'Tls'. Sin embargo, en el caso del espacio con nombre 
'wlpdstm', podríamos agregar una definición de 'pthread_key_t'. Si esto 
fuere el caso, entonces escogeríamos la definición en 'wlpdstm' si no 
usáremos el operador ::. Por ejemplo,

namespace wlpdstm
{

struct pthread_key_t { ... };

template< ... >
class Tls
{
   ...
   static pthread_key_t tlsKey;
   static pthread_key_t initKey;
};

}

Aquí, usaríamos el tipo 'pthread_key_t' de 'wlpdstm', pero si usamos el 
operador de ámbito global, entonces da igual si existen otras 
definiciones de 'pthread_key_t'.

> 3º Líneas 67 y 68. No comprendo estos 2 templates.
> 

Estas líneas se refieren a este código:

template<class T, bool GLOBAL_INIT, bool THREAD_INIT> ::pthread_key_t 
wlpdstm::Tls<T, GLOBAL_INIT, THREAD_INIT>::tlsKey;

template<class T, bool GLOBAL_INIT, bool THREAD_INIT> ::pthread_key_t 
wlpdstm::Tls<T, GLOBAL_INIT, THREAD_INIT>::initKey;

Aquí, estamos definiendo dos variables de tipo 'pthread_key_t' que 
fueron declaradas como miembros estáticos. Como son miembros de una 
estructura-plantilla, tenemos que acceder a la estructura, pero también 
tenemos que referirnos a la plantilla, porque queremos ser genéricos. de 
lo contrario, haríamos esto:

::pthread_key_t wlpdstm::Tls<int,true,false>::tlsKey;

Pero esta definición no serviría para todas las demás que podemos construir.

> 4º Lineas 92 a 95. EL template con el 'inline' seguido. SE supone que
> un inline es una función de tamaño muy pequeño y que definimos de
> esta manera para mayor limpieza. Pero en este inline no encuentro el
> nombre de la función, para después invocarlo. Aparte no entiendo el
> comando después del inline, no veo declaración de variables.
> 

Las líneas son:

template< class T, bool GLOBAL_INIT, bool THREAD_INIT >
inline T *wlpdstm::Tls< T, GLOBAL_INIT, THREAD_INIT >::Get()
{
   return (T *)::pthread_getspecific(tlsKey);
}

El propósito de una función en lína (o 'inline') es que se ejecute 
rápidamente, saltándose el sistema de la invocación normal de las 
funciones. No siempre se puede crear uan función en línea, aunque 
pongamos 'inline', por lo que no es garantizado que sea así.

En cuanto a este código, estamos definiendo la función miembro 'Get()'. 
Por lo tanto, tenemos que escribir todas las "partes" de la definición 
de una función. Esto es:

- Tipo de retorno: T *
- Nombre de la función: wlpdstm::Tls< T, GLOBAL_INIT, THREAD_INIT >::Get

Como 'Tls' es una clase-plantilla, tenemos que definir los parámetros de 
tal plantilla, por lo que colocamos el código de 'template'.

> 5ªLinea 42 --> #ifdef USE_PTHREAD_TLS --> ESto es una instrucción
> para el pre-compilador. Se supone que si la variable
> USE_PTHREAD_TLS='1' se compila lo que esta a continuación y sino no.
> Lo que no entiendo es que en este fichero no se da valor a esa
> variable. Si estamos compilando y se supone que las variables no
> tienen valor, algunas sí, como sabe el compilador que tiene que
> compilar.
> 

Casi. Esta directiva simplemente requiere que tal constante simbólica 
exista. No tiene en cuenta el valor de tal constante, sólo su definición 
previa. Esto implica que en algún momento previo en este código se ha 
escrito algo así:

#define USE_PTHREAD_TLS

Obviamente, tal constante puede definirse con un valor, pero #ifdef no 
toma tal valor en cuenta.

Puedes pensar que tal constante sirve de "banderín": existe o no existe.

> Gracias de antemano.
> Soy un poco novato ocn esto de c++.
> 

De nada; para eso estamos :)


Espero que todo esto aclare las dudas.

Steven





Más información sobre la lista de distribución Cconclase