2010-07-04 17 views
55

¿Cómo puedo forzar que un parámetro de plantilla T sea una subclase de una clase específica Baseclass? Algo como esto:Restringir el parámetro de plantilla de C++ a la subclase

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

} 
+3

¿Qué estás tratando de lograr al hacer esto? – sth

+2

Solo quiero asegurarme de que T sea en realidad una instancia de una subclase o la clase misma. El código dentro de la función que he proporcionado es bastante irrelevante. – phant0m

+6

por el contrario, es muy relevante. Determina si es una buena idea o no poner el trabajo en esa prueba. En muchos (¿todos?) Casos, no hay absolutamente ninguna necesidad de imponer esas restricciones usted mismo, sino dejar que el compilador lo haga al crear instancias. Por ejemplo, para la respuesta aceptada, sería bueno verificar si 'T' deriva de' Baseclass'. A partir de ahora, esa verificación es implícita y no es visible para sobrecargar la resolución. Pero si no se hace tal restricción implícita, no parece haber ninguna razón para una restricción artificial. –

Respuesta

44

En este caso se puede hacer:

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

} 

Esto no va a compilar si T no es una subclase de la clase base (o T es BaseClass).

+0

ah sí, esa es una buena idea. ¡Gracias! ¿Lo tomo entonces no hay forma de definirlo en la definición de la plantilla? – phant0m

+2

@ phant0m: Correcto. No puede restringir explícitamente los parámetros de plantilla (excepto el uso de conceptos, que se consideraron para C++ 0x pero luego se descartaron). Todas las restricciones suceden implícitamente por las operaciones que realiza en él (o, en otras palabras, la única restricción es "El tipo debe admitir todas las operaciones que se realizan en él"). – sepp2k

+1

ah ic. Muchas gracias por la aclaración! – phant0m

0

Llamando a funciones dentro de su plantilla que existen en la clase base.

Si intentas crear una instancia de tu plantilla con un tipo que no tiene acceso a esta función, recibirás un error en tiempo de compilación.

+2

Esto no garantiza que 'T' * sea un *' BaseClass' porque los miembros declarados en 'BaseClass' podrían repetirse en la declaración de' T'. –

5

Usted podría utilizar 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

gracias por la sugerencia. Lo revisaré. – phant0m

8

No es necesario conceptos, pero se puede usar 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 
} 

Tenga en cuenta que esto va a crear una instancia de la función sólo cuando la condición se cumple, pero no proporcionará un error sensible si la condición no se cumple.

+0

¿Qué pasa si ajusta todas las funciones de esta manera? por cierto, ¿qué devuelve? –

+0

El 'enable_if' toma un segundo parámetro de tipo que por defecto es' void'. La expresión 'enable_if < true, int > :: type' representa el tipo' int'. Realmente no puedo entender cuál es tu primera pregunta, puedes usar SFINAE para lo que quieras, pero no entiendo muy bien qué piensas hacer con esto en todas las funciones. –

39

para ejecutar código menos inútil en tiempo de ejecución se puede ver en: http://www.stroustrup.com/bs_faq2.html#constraints que proporciona algunas clases que realizan la prueba de tiempo de compilación de manera eficiente, y producir mensajes de error más agradables.

En particular:

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

gracias por el enlace! – phant0m

+1

Para mí, esta es la mejor y más interesante respuesta. Asegúrate de consultar las preguntas frecuentes de Stroustrup para leer más sobre todo tipo de restricciones que podrías aplicar de manera similar a esto. –

+1

De hecho, ¡esta es una gran respuesta! Gracias. El sitio mencionado se movió aquí: http://www.stroustrup.com/bs_faq2.html#constraints –

54

Con un compilador compatible con C++ 11, se puede hacer algo como esto:

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

He probado esto a cabo usando el compilador gcc 4.8.1 dentro de un entorno CYGWIN, por lo que también debería funcionar en entornos * nix.

+0

Para mí también funciona así: 'plantilla clase BaseBiz { static_assert (std :: is_base_of :: value," TEntity no derivada de BaseEntity ");' ... –

+0

It funciona solo si la plantilla completa está en el encabezado. – peterh

Cuestiones relacionadas