2015-04-10 12 views
8

Ok, sto lavorando con g ++ 4.8.2 e ho il seguente codice (un po 'lungo) che riceve un messaggio di errore su un tipo incompleto. Ho ridotto il codice per un pezzo più piccolo per l'inclusione qui e può essere compilato direttamente:Sizeof failing nel template anche se i tipi sono tutti definiti

#include <cstdlib> 

struct S 
{ 
    void method(){} 
}; 


template<size_t sz, size_t tot> 
class genpool 
{ 
}; 

template <class T> 
class mempool 
{ 
private: 
    genpool<sizeof(T), 10*sizeof(T)> p; 
}; 


template <class obj, class mthd> 
class functor 
{ 
private: 
    static mempool<functor<obj, mthd> > pool; 
}; 

template <class obj, class mthd> 
mempool<functor<obj, mthd> > functor<obj, mthd>::pool; 

int main() 
{ 
    typedef void (S::*m)(); 
    typedef functor<S, m> fctr; 

    fctr f; 
} 

Il messaggio di errore del compilatore è:

g++ jj.C 
jj.C: In instantiation of ‘class mempool<functor<S, void (S::*)()> >’: 
jj.C:30:30: required from ‘class functor<S, void (S::*)()>’ 
jj.C:37:8: required from here 
jj.C:18:17: error: invalid application of ‘sizeof’ to incomplete type ‘functor<S, void (S::*)()>’ 
    genpool<sizeof(T), 10*sizeof(T)> p; 
       ^

Compilation exited abnormally with code 1 at Thu Apr 9 18:50:06 

Ovviamente, il modello funtore è definito sopra e tutti gli argomenti a functor sono stati definiti in modo esplicito. Ciò sembra implicare che la dimensione della funzione dovrebbe essere ben definita. C'è qualcosa che mi manca qui?

--Ron

risposta

0

non credo che si può fare, perché si ha una definizione ricorsiva. Ad esempio, non si può fare questo:

#include <cstdlib> 

class B; 

class A 
{ 
    B b; 
}; 

class B 
{ 
    A a; 
}; 

int main() 
{ 
     A x; 
} 

L'unica via d'uscita è quello di rendere uno dei membri di un puntatore, invece di un'istanza.

1

La tua definizione di functor è ricorsiva. Richiede al compilatore di conoscere la dimensione del tipo di functor durante la determinazione del tipo functor. È possibile generare esattamente lo stesso problema con questo codice:

template <class A> 
class B { 
public: 
    static const int szA = sizeof(A); 
}; 

template <class A> 
class C { 
public: 
    static B<C<A> > b; 
}; 

int main() { 
    C<int> c; 
} 

seconda di ciò che l'applicazione è, si dovrebbe essere in grado di fare ciò che si vuole utilizzare type traits.

+0

ho pensato membri dati statici non contribuirebbe alla dimensione di una classe in modo non dovrebbe esserci alcun ricorsione qui ... –

+0

Non importa quale sia la dimensione della classe sarà alla fine. Nel momento in cui dichiari il membro statico, il compilatore non sa quale sia la dimensione della classe perché non ha finito di dichiarare la classe. – Mokosha

1

Al momento si dichiara poolall'interno di functor, si stanno ancora definendo la classe functor, in modo che il tipo di functor è ancora incompleta.

Questo è simile a trasmettere dichiarazioni:

class functor; 
functor func; <<-incomplete here 
functor *ptr; <<-pointer is fine 
class functor 
{ 
    functor func; <<-incomplete again 
}; 
functor func; <<-now complete definition, ok 
6

Il problema è che il compilatore sta tentando di creare un'istanza di mempool<> prima che esemplifica functor<>. Questo perché il compilatore ritiene necessario poter definire il membro statico functor<>::pool prima che lo stesso functor<> sia considerato completamente definito.

Una soluzione alternativa consiste nel restituire un mempool<> & da una funzione membro statica.

template <class obj, class mthd> 
class functor 
{ 
private: 
    static mempool<functor> & get_pool() { 
    static mempool<functor> pool; 
    return pool; 
    } 
}; 

//template <class obj, class mthd> 
//mempool<functor<obj, mthd> > functor<obj, mthd>::pool; 

Ciò funziona perché il riferimento significa che è bene per mempool<> di rimanere incompleta fino a dopo functor<> viene istanziata. (In realtà, un metodo di un modello non viene istanziato a meno che non vi sia un codice che effettivamente lo chiama). Quando viene chiamato il metodo statico, lo stesso functor<> è completo, quindi l'oggetto statico all'interno di functor<>::get_pool può essere istanziato correttamente.

Come nota laterale, è accettabile passare un tipo incompleto come argomento di un template, ma il modello ha restrizioni su cosa può realmente fare con un tipo incompleto. Tutto è a posto se il modello richiede solo un riferimento o un puntatore al tipo per la sua istanziazione.

+0

Fantastico! Questo ha funzionato perfettamente. –

Problemi correlati