2009-10-12 8 views
5

Estoy leyendo el código fuente STL en este momento. Aunque entiendo lo esencial de lo que estoy leyendo en stl_list.h, quiero comprender completamente el siguiente fragmento (principalmente relacionado con la sintaxis de la plantilla, creo).Una pregunta sobre la sintaxis de la plantilla C++ (código fuente de la biblioteca STL)

plantilla

class _List_base { 
    ... 
    typedef typename _Alloc::template rebind<_List_node<_Tp> >::other _Node_Alloc_type; //(1). 

    ... 
    typedef _Alloc allocator_type; 
    get_allocator() const 
    { return allocator_type(*static_cast< 
          const _Node_Alloc_type*>(&this->_M_impl)); } // (2) 
    ... 
}; 

Puede alguien explicar por qué necesitamos una "plantilla" _Alloc siguiente en la línea (1)? (y dando una explicación completa de esta línea?)

¿Alguien puede explicar por qué podemos convertir _Node_Alloc_type en _Alloc en la línea (2)?

+3

Debe aclarar qué implementación particular de STL está mirando. Mientras que la interfaz STL está estandarizada, la implementación varía de un proveedor a otro. –

Respuesta

12

La palabra clave template es necesaria para identificar el nombre rebind como plantilla de clase. Sin él, rebind podría considerarse una variable o una constante (en este caso un tipo debido a la palabra clave typename) y el siguiente < podría interpretarse como un operador menor que.

Esto es algo similar a la palabra clave typename (que es por supuesto necesaria para identificar other como un tipo).

Se requiere que cada asignador proporcione una metafunción (es decir, una plantilla de clase) llamada rebind que devuelve el mismo asignador pero para un tipo diferente. En otras palabras,

Alloc<T>::rebind<U>::other 

nombres del mismo tipo que

Alloc<U> 

La segunda parte de su pregunta es difícil de responder sin más contexto. ¿Cuál es el tipo de _M_impl? ¿Cómo se define ese tipo?

2

Parece que la implementación de gcc de std :: list. En ese caso, el contexto es:

struct _List_impl : public _Node_Alloc_type { ... }; 
_List_impl _M_impl; 

Y se olvidó de escribir el tipo de retorno de la función miembro:

typedef _Alloc allocator_type; 
allocator_type 
get_allocator() const 
{ return allocator_type(*static_cast<const _Node_Alloc_type*>(&this->_M_impl)); } 

respuesta para (1)

Al añadir una nodo en una lista de tipo _Tp, lo que realmente necesita asignarse no es un objeto _Tp sino un nodo de lista que contiene _Tp (a _List_node<_Tp>).

Por lo tanto, std :: list necesita poder asignar un _List_node<_Tp> pero se le ha proporcionado un asignador para _Tp. Aquí es donde la revinculación plantilla typedef viene muy bien: se hace posible obtener un asignador de tipo U desde un asignador de tipo T.

El uso de este revinculación, obtenemos un _Alloc<_List_node<_Tp> > del tipo _Alloc<_Tp>.


respuesta para (2) en el archivo fuente como comentario:

// NOTA BENE 
// The stored instance is not actually of "allocator_type"'s 
// type. Instead we rebind the type to 
// Allocator<List_node<Tp>>, which according to [20.1.5]/4 
// should probably be the same. List_node<Tp> is not the same 
// size as Tp (it's two pointers larger), and specializations on 
// Tp may go unused because List_node<Tp> is being bound 
// instead. 
// 
// We put this to the test in the constructors and in 
// get_allocator, where we use conversions between 
// allocator_type and _Node_Alloc_type. The conversion is 
// required by table 32 in [20.1.5]. 

Se supone que tipo _Alloc 's es el mismo que _Node_Alloc_type según el estándar de C++; por lo tanto, static_cast afirma que la conversión es legal.

Cuestiones relacionadas