2015-04-10 7 views
8

Ok, ich arbeite mit g ++ 4.8.2 und habe den folgenden (etwas langen) Code, der eine Fehlermeldung über einen unvollständigen Typ erhält. Ich habe den Code auf einen kleineren Brocken für die Aufnahme hier reduziert und kann direkt erstellt werden:Sizeof in Vorlage fehlgeschlagen, obwohl alle Typen definiert sind

#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; 
} 

Die Compiler Fehlermeldung lautet:

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 

Offensichtlich ist die Vorlage Funktors vorstehend definiert ist und alle Argumente zu Funktor wurden explizit definiert. Dies scheint mir zu implizieren, dass die Größe der Funktion gut definiert sein sollte. Gibt es etwas, das mir hier fehlt?

--Ron

Antwort

0

Ich glaube nicht, können Sie es tun, weil Sie eine rekursive Definition haben. Zum Beispiel, können Sie dies nicht tun:

#include <cstdlib> 

class B; 

class A 
{ 
    B b; 
}; 

class B 
{ 
    A a; 
}; 

int main() 
{ 
     A x; 
} 

Der einzige Ausweg ist eines der Mitglieder ein Zeiger statt eine Instanz zu machen.

1

Ihre Definition von functor ist rekursiv. Der Compiler muss die Größe des Typs functor kennen, während er den Typ functor ermittelt. Sie können mit diesem Code genau das gleiche Problem erzeugen:

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

Je nachdem, was Ihre Anwendung ist, sollten Sie in der Lage sein zu tun, was Sie mit type traits wollen.

+0

Ich dachte, statische Datenelemente nicht auf die Größe einer Klasse beitragen würde, so gibt es keine Rekursion hier sein sollte ... –

+0

Es ist egal, was die Größe der Klasse wird schließlich sein. An dem Punkt, an dem Sie den statischen Member deklarieren, weiß der Compiler nicht, wie groß die Klasse ist, da die Klasse noch nicht deklariert wurde. – Mokosha

1

Zu der Zeit erklären Sie poolinnerhalb von functor, Sie sind die functor Klasse noch zu definieren, so functor die Art ist noch unvollständig.

Dies ist ähnlich Erklärungen zu übermitteln:

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

Das Problem ist, dass der Compiler mempool<> zu instanziiert versucht, bevor es functor<> instanziiert. Dies liegt daran, dass der Compiler glaubt, dass er das statische Element functor<>::pool zuerst definieren muss, bevor functor<> selbst als vollständig definiert gilt.

Eine Problemumgehung besteht darin, eine mempool<> & von einer statischen Elementfunktion zurückzugeben. Diese

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; 

funktioniert, weil die Referenzmittel, es ist okay für mempool<> unvollständig zu bleiben, bis nach functor<> instanziiert wird. (Tatsächlich wird eine Methode einer Vorlage nicht instanziiert, es sei denn, es gibt Code, der sie tatsächlich aufruft.) Wenn die statische Methode aufgerufen wird, ist functor<> selbst abgeschlossen, sodass das statische Objekt innerhalb von functor<>::get_pool ordnungsgemäß instanziiert werden kann.

Als Randbemerkung, ist es akzeptabel, einen unvollständigen Typen als Argument an eine Vorlage zu übergeben, aber die Vorlage hat Beschränkungen auf, was es mit einem unvollständigen Typ tatsächlich tun kann. Alles ist in Ordnung, wenn die Vorlage nur eine Referenz oder einen Zeiger auf den Typ für ihre Instanziierung benötigt.

+0

Super! Das hat perfekt funktioniert. –