2016-01-28 42 views
12

Sto cercando di fare una classe annidata che è anche una sottoclasse di suo genitore:sottoclassi nidificati in C++

struct X { struct Y : public X {}; }; 

Purtroppo, questo non sembra essere ammessi in C++, come g ++ produce l'errore

error: invalid use of incomplete type 'struct X'

Tuttavia, il mio codice vero e proprio ha X come una classe template:

template<typename T> struct X 
{ struct Y : public X {}; }; 

ottengo lo stesso messaggio , Ma questa volta è solo un avvertimento:

warning: invalid use of incomplete type 'struct X< T >'

La mia domanda è: perché è il primo caso illegale, mentre il caso su modelli dà solo un avvertimento? La versione del modello funziona esattamente come mi aspetterei che sia (posso creare istanze di , assegnarle a X<T> e così via), ma l'avviso significa che non dovrei usarlo? Quali problemi posso aspettarmi di incontrare se ignoro l'avviso?

+6

Sospetto che nel secondo caso si verifichi un errore anche quando si tenta di istanziare 'X' –

+0

Utilizzare una dichiarazione di inoltro di X? – LiMuBei

+2

@LiMuBei, non puoi ereditare da una classe incompleta (che è una classe inoltrata). questo è il problema. – StoryTeller

risposta

2

Tecnicamente, per quanto riguarda il compilatore è interessato, il layout della base (X) non ha bisogno di essere conosciuto fino a istanziare il modello (X). E il modello (X) non può essere avviato prima che sia completamente definito. A quel punto, è noto il layout.

modo più semplice per un errore dal modello è quello di provare istantiate Y all'interno X:

template<typename T> struct X { 
    struct Y : public X {}; 
    Y y; 
}; 

Nelle versioni precedenti del compilatore, non vi era alcun avviso nel caso in cui si mostra, ma è stato aggiunto ad un certo punto. Ecco una discussione dal GCC bugtracker sul fatto che l'avviso sia spurio. C'era qualche incertezza se questo fosse consentito dallo standard, ma la loro conclusione era che non era permesso.

Quindi, nessuno dei due casi è consentito dallo standard, ma GCC continua a lavorare con quest'ultimo, perché può.

Yam Marcovic Mostra come X::Y può essere definito in modo conforme allo standard. L'esempio identicamente identico è mostrato nel bugtracker gcc.

9

Per rispondere alla domanda di base: viene visualizzato un avviso perché il modello non è stato ancora istanziato, quindi non disturba nessuno.

Il modo per risolvere questo problema, in entrambi i casi, sarebbe definire X::Y nel punto in cui X 'la layout s è già noto, e quindi Y' s la layout può essere adeguatamente dedotta. Si potrebbe fare:

struct X { struct Y; } 
struct X::Y {};