2014-12-22 12 views
7

Un esempio compilabile:modello Esterno per il modello parametrizzata con il tipo incompete

main.cpp

#include "test.h" 

int main(int argc, char* argv[]) { 
    auto myPtr = std::unique_ptr<MyClass>(getMyPtr()); 
} 

test.h

#ifndef TEST_H 
#define TEST_H 

#include <memory> 

class MyClass; 
extern template class std::unique_ptr<MyClass>; 
MyClass* getMyPtr(); 

#endif 

test.cpp

#include "test.h" 

class MyClass {}; 
template class std::unique_ptr<MyClass>; 
MyClass* getMyPtr() { return new MyClass; } 

g ++ 4.9.2 lamenta

In file included from c:/devel/mingw32/i686-w64-mingw32/include/c++/memory:81:0, 
       from main.cpp:4: 
c:/devel/mingw32/i686-w64-mingw32/include/c++/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = MyClass]': 
c:/devel/mingw32/i686-w64-mingw32/include/c++/bits/unique_ptr.h:236:16: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = MyClass; _Dp = std::default_delete<MyClass>]' 
main.cpp:64:53: required from here 
c:/devel/mingw32/i686-w64-mingw32/include/c++/bits/unique_ptr.h:74:22: error: invalid application of 'sizeof' to incomplete type 'MyClass' 
    static_assert(sizeof(_Tp)>0, 
        ^

anche se MyClass dovrebbero essere visibili al punto di modello di un'istanza. Perché?

Modifica: corretto un errore nell'esempio.

+0

'extern classe template std :: unique_ptr ;' è questa linea mancano alcune un simbolo? 'extern template class std :: unique_ptr my_symbol;' Anche l'altro da 'test.cpp':' template class std :: unique_ptr my_symbol; ' –

+3

@ πάνταῥεῖ: in realtà, non manca affatto un simbolo! Questa dichiarazione dice al compilatore che un'altra unità di traduzione fornirà l'istanza del modello di classe corrispondente! –

+0

@ DietmarKühl Ah, THX per chiarimenti. Non sapevo ancora questa sintassi. Imparo qualcosa di nuovo qui ogni giorno MrGreen. –

risposta

6

Gli effetti di dichiarazioni di istanza, vale a dire, una garanzia che il modello non viene creata un'istanza implicitamente, non si applica a inline funzioni secondo 14.7.2 [temp.explicit] paragrafo 10:

Tranne per funzioni inline, dichiarazioni con tipi dedotti dal loro inizializzatore o valore di ritorno (7.1.6.4), variabili const di tipi letterali, variabili di tipi di riferimento e specializzazioni di modelli di classe, le dichiarazioni di istanziazione esplicite hanno l'effetto di sopprimere l'istanza implicita dell'entità a cui si riferiscono [Nota: l'intento è che una funzione inline che è l'oggetto di una dichiarazione di istanziazione esplicita sarà ancora istanziata in modo implicito quando si utilizza odr (3.2) in modo che il corpo possa essere considerato per l'inlining, ma che nessuna copia out-of-line della funzione inline sarebbe generato nella traduzione unit.-end nota]

la libreria standard è chiaramente libero di dichiarare qualsiasi delle sue funzioni inline. Cioè, l'uso di una dichiarazione di istanza non influenza il requisito sui tipi che vengono definiti con la classe template di libreria standard (se non diversamente specificato, ovviamente). gcc definisce il distruttore per std::unique_ptr<...> nella definizione di questo modello di classe rendendolo implicitamente in linea. Qui è una fonte di esempio che dimostra il problema: a seconda se DECL_ONY è definito esso compilatore o no:

template <typename T> 
struct foo 
{ 
    ~foo() 
#ifdef DECL_ONLY 
     ; 
#else 
    { static_assert(sizeof(T), "defined!"); } 
#endif 
}; 

#ifdef DECL_ONLY 
template <typename T> 
foo<T>::~foo() { static_assert(sizeof(T), "defined!"); } 
#endif 

class MyClass; 
extern template struct foo<MyClass>; 

int main(int , char* []) { 
    foo<MyClass> f; 
} 
+2

Ho provato anche a extern il modello default_delete, ha ricevuto lo stesso messaggio. – Smiles

+1

@Cynic: abbastanza giusto. Il problema è, in effetti, qualcosa di diverso: le funzioni "in linea" sono esentate dall'intervento estemporaneo esterno e le funzioni sono definite [implicitamente] "in linea". –

+0

Ho appena dato per scontato che in questo caso venga generata una versione fuori linea della funzione, come con i virtual inline.Ora vedo che non c'era alcun motivo per supporre che (a causa della creazione di istanze esplicite in una diversa unità di compilazione). – Smiles

Problemi correlati