2010-07-04 15 views
55

Come posso forzare un parametro modello T ad essere una sottoclasse di una classe specifica Baseclass? Qualcosa di simile a questo:Limita il parametro modello C++ alla sottoclasse

template <class T : Baseclass> void function(){ 
    T *object = new T(); 

} 
+3

Cosa stai cercando di ottenere facendo questo? – sth

+2

Voglio solo assicurarmi che T sia effettivamente un'istanza di una sottoclasse o della classe stessa. Il codice all'interno della funzione che ho fornito è praticamente irrilevante. – phant0m

+6

al contrario, è molto rilevante. Determina se è una buona idea o non mettere il lavoro in quel test. In molti casi (tutti?), Non è assolutamente necessario applicare tali vincoli da soli, ma piuttosto consentire al compilatore di eseguirlo durante l'istanziazione. Ad esempio, per la risposta accettata, sarebbe opportuno verificare se 'T' deriva da' Baseclass'. A partire da ora, tale controllo è implicito e non è visibile alla risoluzione di sovraccarico. Ma se non viene eseguito un simile vincolo implicito, non sembra esserci alcuna ragione per una restrizione artificiale. –

risposta

44

In questo caso si può fare:

template <class T> void function(){ 
    Baseclass *object = new T(); 

} 

Questo non compilare se T non è una sottoclasse di BaseClass (o T è BaseClass).

+0

ah sì, è una buona idea. Grazie! Lo prendo quindi non c'è modo di definirlo nella definizione del template? – phant0m

+2

@ phant0m: corretto. Non è possibile vincolare in modo esplicito i parametri del modello (eccetto l'uso di concetti, che sono stati considerati per C++ 0x ma poi rilasciati). Tutti i vincoli avvengono implicitamente dalle operazioni eseguite su di esso (o in altre parole l'unico vincolo è "Il tipo deve supportare tutte le operazioni eseguite su di esso"). – sepp2k

+1

ah ic. Grazie mille per il chiarimento! – phant0m

0

Chiamando le funzioni all'interno del modello esistenti nella classe base.

Se si tenta di creare un'istanza del modello con un tipo che non ha accesso a questa funzione, si riceverà un errore in fase di compilazione.

+2

Ciò non garantisce che 'T' * sia un *' BaseClass' perché i membri dichiarati in 'BaseClass' possono essere ripetuti nella dichiarazione di' T'. –

5

Si potrebbe utilizzare Boost Concept Check s' BOOST_CONCEPT_REQUIRES:

#include <boost/concept_check.hpp> 
#include <boost/concept/requires.hpp> 

template <class T> 
BOOST_CONCEPT_REQUIRES(
    ((boost::Convertible<T, BaseClass>)), 
(void)) function() 
{ 
    //... 
} 
+0

grazie per il suggerimento. Controllerò. – phant0m

8

Non hai bisogno di concetti, ma è possibile utilizzare SFINAE:

template <typename T> 
boost::enable_if< boost::is_base_of<Base,T>::value >::type function() { 
    // This function will only be considered by the compiler if 
    // T actualy derived from Base 
} 

Nota che questo istanziare la funzione solo quando la condizione è soddisfatto, ma non fornirà un errore ragionevole se la condizione non è soddisfatta.

+0

Cosa succede se avvolgi tutte le funzioni in questo modo? btw cosa restituisce? –

+0

Il parametro 'enable_if' richiede un secondo parametro di tipo che per impostazione predefinita' void'. L'espressione 'enable_if < true, int > :: type' rappresenta il tipo 'int'. Non riesco davvero a capire quale sia la tua prima domanda, puoi usare SFINAE per tutto ciò che desideri, ma non capisco cosa intendi fare con questo su tutte le funzioni. –

39

per eseguire codice meno inutile in fase di esecuzione si può guardare: http://www.stroustrup.com/bs_faq2.html#constraints che prevede alcune classi che svolgono in modo efficiente il test di tempo di compilazione, e produrre i messaggi di errore più belli.

In particolare:

template<class T, class B> struct Derived_from { 
     static void constraints(T* p) { B* pb = p; } 
     Derived_from() { void(*p)(T*) = constraints; } 
}; 

template<class T> void function() { 
    Derived_from<T,Baseclass>(); 
} 
+1

grazie per il link! – phant0m

+1

Per me, questa è la risposta migliore e più interessante. Assicurati di controllare le FAQ di Stroustrup per saperne di più su tutti i tipi di vincoli che potresti applicare in questo modo. –

+1

In effetti, questa è una risposta infernale! Grazie. Il sito menzionato viene spostato qui: http://www.stroustrup.com/bs_faq2.html#constraints –

54

Con un C++ 11 compilatore compatibile, si può fare qualcosa di simile:

template<class Derived> class MyClass { 

    MyClass() { 
     // Compile-time sanity check 
     static_assert(std::is_base_of<BaseClass, Derived>::value, "Derived not derived from BaseClass"); 

     // Do other construction related stuff... 
     ... 
    } 
} 

Ho provato questo utilizzando il compilatore gcc 4.8.1 all'interno di un ambiente CYGWIN - quindi dovrebbe funzionare anche in ambienti * nix.

+0

Per me funziona anche in questo modo: 'template class BaseBiz { static_assert (std :: is_base_of :: value," TEntity non derivato da BaseEntity ");' ... –

+0

It funziona solo se l'intero modello è nell'intestazione. – peterh

Problemi correlati