Ci sono già un buon numero di domande su unique_ptr e tipo incompleto su SO, ma nessuno può darmi un concetto per capire perché il seguente non lavoro:C++ 11: unique_ptr si lamenta del tipo incompleto, ma non quando lo avvolgo
// error: ... std::pair<...>::second has incomplete type
template<typename K, typename T> struct Impl {
typedef typename std::unordered_map<K,Impl<K,T>>::iterator iter_type;
std::unique_ptr<iter_type> ptr;
Impl() : ptr(new iter_type()) {}
};
int main() { Impl<int,int>(); return 0; }
mentre la successiva fa:
template<typename K, typename T> struct Impl {
struct Wrapper {
typedef typename std::unordered_map<K,Impl<K,T>>::iterator iter_type;
iter_type iter;
};
std::unique_ptr<Wrapper> ptr;
Impl() : ptr(new Wrapper()) {}
};
int main() { Impl<int,int>(); return 0; }
non vedo dove la differenza tecnica è: Se std::pair<...>::second
(cioè, Impl<K,T>
) era incompleta Impl
nel primo esempio, dovrebbe essere incompleto t o Wrapper
anche nel secondo. Inoltre, quando è sufficiente avvolgere il unique_ptr
in una struttura, perché esiste una restrizione per il primo caso?
UPDATE:
Dopo la risposta di Dietmar Kühl, penso che il problema può essere ridotto al seguente:
template<typename K, typename T> struct Impl {
typename std::unordered_map<K,Impl<K,T>>::iterator ptr;
};
vs
template<typename K, typename T> struct Impl {
struct Wrapper {
typename std::unordered_map<K,Impl<K,T>>::iterator iter;
};
Wrapper *ptr;
};
Intendi dire che la differenza è che il costruttore 'Wrapper' non è compilato prima che la classe' Impl' sia ** considerata ** completamente implementata? Quindi il Wrapper sta semplicemente rendendo artificialmente la costruzione dell'intero processo in due fasi quando l'ordine di compilazione potrebbe essere esattamente lo stesso? –
@JoSo: i membri dei modelli di classe vengono istanziati quando utilizzati. 'Wrapper' è un membro di un modello di classe e viene utilizzato solo nella definizione del costruttore. Il 'typedef' non è realmente un membro e per definire il modello di classe' Impl' è una specie di istanza. Quindi, sì, rendendolo un processo a due stadi evita il problema del tipo non ancora definito. –
Non dovrebbe esserci un modo per dire al compilatore "sì, questo tipo esiste davvero!" ?. Voglio dire, posso anche dire 'struct NewType; NewType * ptr; 'all'interno della classe senza mai definire NewType e funziona! Questa è solo una debolezza delle specifiche/implementazione o ci sono ragioni più profonde dietro di essa? –