2011-12-15 12 views
5

Mam funkcję szablonu i chcę zapewnić podczas kompilacji, że nie jest ona tworzona na podtypie lub nadtypie danej klasy.Jak mogę utworzyć kompilację czasu, że szablon ma określony typ?

Jak mogę spowodować błąd kompilatora C++, jeśli jest naruszony?

class base { 
}; 
class derived : public base { 
}; 
class lowest : public derived { 
}; 

template <typename T> 
bool isCorrect(const T& obj) { 
    typedef foo<T> D; 
    foo<T> *def = foo<T>::find(); 
    return (def && def->getAnswer(object)); 
} 

Chcę isCorrect aby być dostępne tylko dla klasy derived, ale nie base lub lowest. Zauważ, że może być wiele innych najniższych klas i ciąg klas podstawowych do wykluczenia, a także alternatywne klasy pochodne, które są dopuszczalne.

Czy istnieje sposób w C++, aby ograniczyć szablon do zastosowania tylko do klas pochodnych, które ja jawnie określić?

+0

możliwe duplikat [Wiązania szablonów C++] (http://stackoverflow.com/questions/122316/template-constraints-c) –

+0

W szczególności może to być przydatne: http://www.boost.org/doc/libs/1_48_0/libs/concept_check/concept_check.htm –

+0

Dlaczego po prostu nie piszesz przeciążenia? – GManNickG

Odpowiedz

4

Oto jedna z technik, które znam.

Najpierw utwórz kolejną klasę szablonów policy_enforcer. Zadeklarować tę klasę bez definiowania go, a także specjalizację z nim przez derivedktóry jest również zdefiniowane:

template<typename T> struct policy_enforcer; 
template<> struct policy_enforcer<derived> { }; 

Następnie wewnątrz funkcji chcesz zablokować, to wyrażenie sizeof(policy_enforcer<T>). Ponieważ sizeof na niekompletnych typach jest błędem kompilacji, uniemożliwi to kompilację kodu.

Aktualizacja z kodem na żywo:using base, using derived, using lowest.

+0

Trochę tępo, ale to by działało. Mam nadzieję, że ktoś opublikuje sposób, który nie jest tak niejasny. – WilliamKF

9

Cechy szczególne, w szczególności is_base_of.

#include <type_traits> 

template <typename T> 
bool isCorrect(const T& obj) { 
    static bool const is_base = std::is_base_of<base, T>::value; 
    static bool const derives = std::is_base_of<derived, T>::value; 
    // specify allowed types here 
    static bool const is_derived = std::is_same<T, derived>::value; 
    // --- 
    static_assert((!is_base && !derives) || is_derived, "wrong argument type"); 

    typedef foo<T> D; 
    foo<T> *def = foo<T>::find(); 
    return (def && def->getAnswer(object)); 
} 

Należy zauważyć, że jest to specyficzne dla C++ 11, ale można uzyskać takie samo zachowanie w Boost.TypeTraits.

1

Możesz użyć specjalizacji szablonów.

Możesz wdrożyć tylko isCorrect tylko dla typów, z którymi chcesz pracować.

Dla innych typów można zaimplementować metodę sztuczną, zwracając na przykład false lub w ogóle nie implementować isCorrect, w takim przypadku nie będzie ona kompilowana dla innych typów.

#include <iostream> 

using namespace std; 

class base { 
}; 
class derived : public base { 
}; 
class lowest : public derived { 
}; 

// using this it will fail if you try to pass anything 
// else than `derived` 
// template <typename T> 
//  bool isCorrect(const T& obj); 

template <typename T> 
bool isCorrect(const T& obj) { 
    cout << __PRETTY_FUNCTION__ << endl; 
    return false; 
} 

template <> 
bool isCorrect<derived>(const derived& obj) { 
    cout << __PRETTY_FUNCTION__ << endl; 
    return true; 
// typedef foo<derived> D; 
// foo<derived> *def = foo<derived>::find(); 
// return (def && def->getAnswer(object)); 
} 

testu:

int main() 
{ 
    base b; 
    derived d; 
    lowest l; 

    cout << isCorrect(b) << endl; 
    cout << isCorrect(d) << endl; 
    cout << isCorrect(l) << endl; 
} 

wyjściowa:

bool isCorrect(const T&) [with T = base] 
0 
bool isCorrect(const T&) [with T = derived] 
1 
bool isCorrect(const T&) [with T = lowest] 
0 
+0

'__func__' jest odpowiednikiem C++ 11' __FUNCTION__', '__PRETTY_FUNCTION__' itp. – Xeo

+0

To nie jest odpowiednik ... Po pierwsze, nie widzę żadnego wymagania dla C++ 11, cokolwiek jest nie tak z' __PRETTY_FUNCTION__ ', to nie było częścią pytania, dzięki dzięki za info :)? Z '__func__' lub' __FUNCTION__' otrzymujesz tylko 'isCorrect' lub' isCorrect ', więc nie widzisz innych typów, które nazywają wersję nie wyspecjalizowaną ... – stefanB

+0

Nic złego, chciałem tylko wspomnieć o tym, ponieważ C++ 11 jest aktualnym standardem. Cała reszta ('__FUNCTION__',' __PRETTY_FUNCTION__', itp.) Jest w większości przypadków niestandardowa i nieprzenośna. :) – Xeo

Powiązane problemy