2015-04-10 11 views
8

Ok, pracuję z g ++ 4.8.2 i mam następujący (nieco długi) kod, który otrzymuje komunikat o błędzie na temat niekompletnego typu. Mam zmniejszone kodu w mniejszym fragmencie włączenia tutaj i może być zestawiane bezpośrednio:Błąd rozmiaru w szablonie, mimo że wszystkie typy są zdefiniowane

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

Komunikat o błędzie kompilatora jest:

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 

Oczywiście funktor szablon jest określony powyżej, a wszystkie argumenty do funktora zostały wyraźnie zdefiniowane. Wydaje się to sugerować, że funkcja sizeof powinna być dobrze zdefiniowana. Czy jest tu coś, czego mi tutaj brakuje?

--Ron

Odpowiedz

0

I nie sądzę, że można to zrobić, bo trzeba rekurencyjną definicję. Na przykład, nie można tego zrobić:

#include <cstdlib> 

class B; 

class A 
{ 
    B b; 
}; 

class B 
{ 
    A a; 
}; 

int main() 
{ 
     A x; 
} 

Jedynym wyjściem jest, aby jeden z członków wskaźnik zamiast instancji.

1

Twoja definicja functor jest rekurencyjna. Wymaga kompilator znać rozmiar typu functor podczas określania typu functor. Można generować dokładnie ten sam problem z tym kodem:

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

W zależności od tego, co aplikacja jest, powinieneś być w stanie robić to, co chcesz za pomocą type traits.

+0

Myślałem statycznymi członkami danych nie przyczyniłoby się do wielkości klasy, więc nie powinno być żadnych rekursji tutaj ... –

+0

Nie ma znaczenia, jaka wielkość klasy ostatecznie będzie. W momencie, gdy deklarujesz element statyczny, kompilator nie wie, jaki jest rozmiar klasy, ponieważ nie zakończył deklarowania klasy. – Mokosha

1

W czasie zadeklarować poolwewnątrz z functor, nadal definiując klasę functor, więc typ functor jest jeszcze niekompletna.

ta jest podobna do przekazania deklaracji:

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

Problem polega na tym, że kompilator próbuje instancję mempool<> przed instancję functor<>. Dzieje się tak dlatego, że kompilator uważa, że ​​musi być w stanie zdefiniować statyczny element członkowski functor<>::pool najpierw, zanim zostanie uznany za w pełni zdefiniowany.

Rozwiązaniem jest zwrócenie mempool<> & z funkcji statycznego elementu.

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; 

To działa, ponieważ odniesienia oznacza, że ​​jest w porządku dla mempool<> pozostanie niekompletne aż po functor<> jest tworzony. (W rzeczywistości metoda szablonu nie jest instancjonowana, chyba że istnieje kod, który faktycznie ją wywołuje.) Gdy wywoływana jest metoda statyczna, sama nazwa functor<> jest kompletna, więc obiekt statyczny z zakresu functor<>::get_pool może być poprawnie utworzony.

Na marginesie, to jest do zaakceptowania przechodzą niepełny typ jako argument szablonu, ale szablon ma ograniczeń co może rzeczywiście zrobić z niekompletną typu. Wszystko jest w porządku, jeśli szablon wymaga tylko odniesienia lub wskaźnika do typu w celu jego utworzenia.

+0

Awesome! To działało idealnie. –

Powiązane problemy