2009-10-12 8 views
5

Sto leggendo il codice sorgente STL al momento. Anche se capisco la carne in quello che sto leggendo in stl_list.h, voglio comprendere appieno il seguente frammento (principalmente correlato alla sintassi del template, penso).Una domanda sulla sintassi del template C++ (codice sorgente della libreria STL)

modello

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) 
    ... 
}; 

qualcuno può spiegare il motivo per cui abbiamo bisogno di un "modello" a seguito _Alloc in linea (1)? (e dando una spiegazione completa di questa linea?)

Qualcuno può spiegare perché possiamo trasmettere _Node_Alloc_type a _Alloc in linea (2)?

+3

È necessario chiarire quale particolare implementazione di STL si sta guardando. Mentre l'interfaccia STL è standardizzata, l'implementazione varia da un fornitore all'altro. –

risposta

12

La parola chiave template è necessaria per identificare il nome rebind come modello di classe. Senza di esso, rebind potrebbe essere considerato una variabile o una costante (in questo caso un tipo dovuto alla parola chiave typename) e il seguente < potrebbe essere interpretato come un operatore inferiore.

Questo è un po 'simile alla parola chiave typename (che è ovviamente necessario per identificare other come tipo).

Ogni allocatore è necessario per fornire una meta-funzione (ad esempio un modello di classe) denominata rebind che restituisce lo stesso allocatore ma per un tipo diverso. In altre parole,

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

nomi dello stesso tipo di

Alloc<U> 

La seconda parte della tua domanda è difficile rispondere, senza più contesto. Qual è il tipo di _M_impl? Come viene definito quel tipo?

2

Sembra l'implementazione gcc di std :: list. In tal caso, il contesto è:

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

E ti sei dimenticato di scrivere il tipo di ritorno della funzione membro:

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

Risposta per (1)

Quando si aggiunge un nodo in un elenco di tipo _Tp, ciò che realmente deve essere assegnato non è un oggetto _Tp ma un nodo elenco contenente _Tp (a _List_node<_Tp>).

Quindi lo std :: elenco deve essere in grado di allocare un _List_node<_Tp> ma è stato fornito un allocatore per _Tp. È qui che il modello typedef rebind risulta utile: consente di ottenere un allocatore per il tipo U da un allocatore per il tipo T.

Utilizzando questo rebind, otteniamo un _Alloc<_List_node<_Tp> > dal tipo _Alloc<_Tp>.


Risposta per (2) nel file di origine come commento:

// 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]. 

Si presume che tipo _Alloc s' è lo stesso di _Node_Alloc_type secondo standard C++; quindi il static_cast afferma che la conversione è legale.

Problemi correlati