2011-12-15 10 views
5

Ho una funzione di modello e desidero assicurare in fase di compilazione che non sia istanziata su un sottotipo o supertipo di una particolare classe.Come posso creare un'asserzione del tempo di compilazione secondo cui un modello è di tipi specifici?

Come posso causare un errore del compilatore C++ se questo viene violato?

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

voglio isCorrect di essere a disposizione per la classe derived solo, ma non base o lowest. Si noti che potrebbero essere presenti molte altre classi inferiori e una stringa di classi di base da escludere, nonché classi derivate alternative accettabili.

Esiste un modo in C++ per limitare il modello a essere applicato solo alle classi derivate specificate in modo esplicito?

+0

possibile duplicato del [Vincoli modelli C++] (http://stackoverflow.com/questions/122316/template-constraints-c) –

+0

In particolare, questo potrebbe essere utile: http://www.boost.org/doc/libs/1_48_0/libs/concept_check/concept_check.htm –

+0

Perché non si limitano a scrivere sovraccarichi? – GManNickG

risposta

4

Ecco una tecnica che conosco.

Innanzitutto, creare un'altra classe modello policy_enforcer. Dichiarare questa classe senza definirlo, e anche fornire una specializzazione di esso per derivedche viene anche definito:

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

Poi, all'interno della funzione che si desidera bloccare, di includere l'espressione sizeof(policy_enforcer<T>). Poiché sizeof su tipi incompleti è un errore di compilazione, ciò impedirà la compilazione del codice.

aggiornata con il codice dal vivo:using base, using derived, using lowest.

+0

Un po 'ottuso, ma funzionerebbe. Spero che qualcuno pubblichi un modo che non è così oscuro. – WilliamKF

9

Tipo tratti, in particolare 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)); 
} 

Si noti che questo è specifico C++ 11, ma è possibile ottenere lo stesso comportamento con Boost.TypeTraits.

1

È possibile utilizzare la specializzazione del modello.

È possibile implementare solo lo isCorrect solo per i tipi con cui si desidera poter lavorare.

Per gli altri tipi è possibile implementare il metodo fittizio, ad esempio restituendo false oppure non implementare lo standard isCorrect, nel qual caso non verrà compilato per altri tipi.

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

prova:

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

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

uscita:

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__' è l'equivalente in C++ 11 di' __FUNCTION__', '__PRETTY_FUNCTION__' ecc. – Xeo

+0

Non è equivalente .... In primo luogo, non vedo alcun requisito per C++ 11, qualcosa di sbagliato con' __PRETTY_FUNCTION__ ', non era parte della domanda, grazie per le informazioni :)? Con '__func__' o' __FUNCTION__' si ottiene 'isCorrect' o' isCorrect 'così non si vedono gli altri tipi che hanno chiamato la versione non specializzata .... – stefanB

+0

Niente di male, volevo solo dirlo, poiché C++ 11 è lo standard corrente. Tutto il resto ('__FUNCTION__',' __PRETTY_FUNCTION__', ecc.) Non è standard e non è portatile la maggior parte del tempo. :) – Xeo

Problemi correlati