[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