¿Cómo puedo forzar que un parámetro de plantilla Tsea una subclase de una clase específica Baseclass? Algo como esto:
template <class T : Baseclass> void function(){
T *object = new T();
}
¿Cómo puedo forzar que un parámetro de plantilla Tsea una subclase de una clase específica Baseclass? Algo como esto:
template <class T : Baseclass> void function(){
T *object = new T();
}
Tderiva de Baseclass. A partir de ahora, esa verificación está implícita y no es visible para sobrecargar la resolución. Pero si en ninguna parte se aplica tal restricción implícita, no parece haber razón para una restricción artificial.
Respuestas:
En este caso puedes hacer:
template <class T> void function(){
Baseclass *object = new T();
}
Esto no se compilará si T no es una subclase de Baseclass (o T es Baseclass).
Con un compilador compatible con C ++ 11, 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...
...
}
}
Probé esto usando el compilador gcc 4.8.1 dentro de un entorno CYGWIN, por lo que también debería funcionar en entornos * nix.
template<class TEntity> class BaseBiz { static_assert(std::is_base_of<BaseEntity, TEntity>::value, "TEntity not derived from BaseEntity");...
Para ejecutar código menos inútil en tiempo de ejecución, puede consultar: 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 producen 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>();
}
unused variable 'p'y unused variable 'pb'?
(void)pb;después B* pb = p;.
No necesita conceptos, pero 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 creará una instancia de la función solo cuando se cumpla la condición, pero no proporcionará un error sensible si no se cumple la condición.
enable_iftoma un segundo parámetro de tipo predeterminado void. La expresión enable_if< true, int >::typerepresenta el tipo int. Realmente no puedo entender cuál es su primera pregunta, puede usar SFINAE para lo que desee, pero no entiendo muy bien qué pretende hacer con esto en todas las funciones.
Desde C ++ 11 no necesita Boost o static_assert. C ++ 11 introduce is_base_of y enable_if. C ++ 14 introduce el tipo de conveniencia enable_if_t, pero si está atascado con C ++ 11, simplemente puede usar enable_if::typeen su lugar.
La solución de David Rodríguez se puede reescribir de la siguiente manera:
#include <type_traits>
using namespace std;
template <typename T>
enable_if_t<is_base_of<Base, T>::value, void> function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
Desde C ++ 17, tenemos is_base_of_v. La solución se puede volver a escribir en:
#include <type_traits>
using namespace std;
template <typename T>
enable_if_t<is_base_of_v<Base, T>, void> function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
También puede limitar la plantilla completa. Puede utilizar este método para definir clases completas. Observe cómo enable_if_tse ha eliminado el segundo parámetro de (anteriormente se había configurado como nulo). Su valor predeterminado es en realidad void, pero no importa, ya que no lo estamos usando.
#include <type_traits>
using namespace std;
template <typename T,
typename = enable_if_t<is_base_of_v<Base, T>>>
void function() {
// This function will only be considered by the compiler if
// T actualy derived from Base
}
De la documentación de los parámetros de la plantilla, vemos que typename = enable_if_t...es un parámetro de la plantilla con un nombre vacío. Simplemente lo usamos para asegurarnos de que existe una definición de tipo. En particular, enable_if_tno se definirá si Baseno es una base de T.
La técnica anterior se da como ejemplo en enable_if.
template <class T : Base>
Se podría usar Boost Concepto Comprobar '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()
{
//...
}
Llamando a funciones dentro de su plantilla que existen en la clase base.
Si intenta crear una instancia de su plantilla con un tipo que no tiene acceso a esta función, recibirá un error en tiempo de compilación.
T sea un BaseClass porque los miembros declarados en BaseClasspodrían repetirse en la declaración de T.