2014-05-19 11 views
9

To pytanie rozważa wyraźną instancję klas szablonów.W jaki sposób jawnie inicjować podstawowe klasy szablonów?

Należy wziąć pod uwagę szablon klasy B<T> pochodzący z innej klasy szablonu A<T>. Chcę jednoznacznie zainicjować B<T>, ponieważ jego metody mają być wywoływane z dynamicznego łączenia, więc metody muszą zostać zainicjowane, chociaż nie są wywoływane w samym kodzie. Oczywiście, będą również wywoływane metody odziedziczone po A<T>, więc muszą one również zostać wdrożone.

Wydaje się, że C++ robi NOT instanciate klas bazowych, gdy wyraźnie instanciating klasę szablonu, jak poprosił w tej kwestii: Do Explicit Instantiations of C++ Class Templates Instantiate Dependent Base Classes? Przykład:

template<typename T> 
class A{ void foo(){...} }; 

template<typename T> 
class B : public A<T> {} 

template class B<int>; // This will NOT instanciate A<int>::foo()!!! 

Oczywiście, ja też trzeba instanciate wszystkich klas bazowych. Jednak nie chcę obciążać kodu klienta tym, ponieważ hierarchia klas może być bardzo głęboka. Rozważ hierarchię klas obejmującą 10 lub więcej klas szablonów. Nie należy nakłaniać klienta do napisania 10 jawnych instancji szablonów. To nie tylko dużo pisania; to również się złamie, gdy wprowadzę zmiany w hierarchii klas.

Zamiast tego, chcę osiągnąć w jakiś sposób, że zawsze, gdy tylko zostanie podana B<T>, wszystkie klasy bazowe też. Próbowałem po prostu wprowadzić podstawową klasę w samym B:

template<typename T> 
class B : public A<T> { 
    template class A<T>; // Does not compile! 
} 

Ale to się nie kompiluje. Czy są inne sposoby na osiągnięcie tego?

Odpowiedz

2

Może nie eleganckie, ale przynajmniej wykonalne: dostarczenie makro instancji szablonu i wymagać od użytkownika, aby użyć makra zamiast ręcznego instancji:

// in A.hpp 
#define INSTANTIATE_A(T) template class A<T>; 

// in B.hpp 
#define INSTANTIATE_B(T) \ 
    INSTANTIATE_A(T)  \ 
    template class B<T>; 

A jeśli wolisz „zanieczyścić” interfejsu klasy aby wymusić użycie makra instancji: dodaj element protected, który wywołuje wszystkie inne funkcje składowe szablonu i wersję w klasie bazowej. Przykład:

template<typename T> 
class A 
{ 
    void foo() {...} 
protected: 
    void instantiate() { foo(); } 
}; 

template<typename T> 
class B : public A<T> 
{ 
    void bar() {...} 
protected: 
    void instantiate() { A<T>::instantiate(); bar(); } 
}; 

template class B<int>; // Now works as expected 

Aktualizacja:

Alternatywa dla drugiego rozwiązania: podejmują wskaźnik funkcji wszystkich członków i zapisać je do zmiennej tymczasowej:

template<typename T> 
class A 
{ 
    void foo() {...} 
protected: 
    void instantiate() { void (A::*p)() = &A::foo; } 
}; 

template<typename T> 
class B : public A<T> 
{ 
    void bar() {...} 
protected: 
    void instantiate() { A<T>::instantiate(); void (B::*p)() = &B::foo; } 
}; 
+0

Problem z drugiego rozwiązania jest to, że niektóre metody mają duże podpisy i nie jest łatwo wytworzyć wartości, które można wykorzystać w metodach. Pierwszy działałby, ale jest rzeczywiście brzydki :(. – gexicide

+0

Dodano wariant drugiego rozwiązania, mimo że jest to prawie tak samo gadatliwe i niezbyt potrzebne: chodzi o to, że 'instantiate()' nigdy naprawdę nie jest wykonywane. –

+0

Dobra, to jest bardziej realny, ale mimo to interfejsy są duże, więc wyliczenie wszystkich metod jest znacznie więcej pracy niż wyliczenie wszystkich klas bazowych. Mam nadzieję, że są inne sposoby, ale dzięki za odpowiedź. – gexicide

Powiązane problemy