programar - template en c++ pdf
Restricciones de plantillas C++ (9)
En C #, podemos definir un tipo genérico que impone restricciones a los tipos que se pueden usar como parámetro genérico. El siguiente ejemplo ilustra el uso de restricciones genéricas:
interface IFoo
{
}
class Foo<T> where T : IFoo
{
}
class Bar : IFoo
{
}
class Simpson
{
}
class Program
{
static void Main(string[] args)
{
Foo<Bar> a = new Foo<Bar>();
Foo<Simpson> b = new Foo<Simpson>(); // error CS0309
}
}
¿Hay alguna manera de imponer restricciones para los parámetros de plantilla en C ++?
C ++ 0x tiene soporte nativo para esto, pero estoy hablando de C ++ estándar actual.
"Implícitamente" es la respuesta correcta. Las plantillas crean efectivamente un escenario de "tipado de pato", debido a la forma en que se compilan. Puede llamar a cualquier función que desee con un valor de tipo plantilla, y las únicas instancias que se aceptarán son aquellas para las que se define ese método. Por ejemplo:
template <class T>
int compute_length(T *value)
{
return value->length();
}
Podemos llamar a este método en un puntero a cualquier tipo que declare el método length()
para devolver un int
. Así que:
string s = "test";
vector<int> vec;
int i = 0;
compute_length(&s);
compute_length(&vec);
... pero no en un puntero a un tipo que no declara length()
:
compute_length(&i);
Este tercer ejemplo no se compilará.
Esto funciona porque C ++ compila una nueva versión de la función (o clase) templada para cada instanciación. A medida que realiza esa compilación, realiza una sustitución directa, casi como una macro, de la instanciación de la plantilla en el código antes de la verificación de tipo. Si todo sigue funcionando con esa plantilla, entonces procede la compilación y finalmente llegamos a un resultado. Si algo falla (como int*
no declarando length()
), entonces obtenemos el temido error de tiempo de compilación de seis páginas.
Como alguien más ha mencionado, C ++ 0x está integrando esto en el lenguaje. Hasta entonces, recomendaría las sugerencias de Bjarne Stroustrup para las restricciones de la plantilla .
Editar: Boost también tiene una alternativa propia .
Edit2: Parece que los conceptos se han eliminado de C ++ 0x .
Echa un vistazo a Boost
Boost Concept Check Library (BCCL)
La biblioteca Concept Check permite agregar una declaración explícita y verificar concepts en el estilo de la extensión de lenguaje C ++ propuesta .
Más o menos Si has static_cast a IFoo *, será imposible crear una instancia de la plantilla a menos que la persona que llama pase una clase que se puede asignar a un IFoo *.
Mire el patrón CRTP (Curiously Recursive Template Pattern). Está diseñado para ayudar a soportar la herencia estática.
Puedes hacerlo. Crea la plantilla base. Haz que tenga solo constructores privados. A continuación, cree especializaciones para cada caso que desee permitir (o haga lo contrario si la lista no permitida es mucho más pequeña que la lista permitida).
El compilador no le permitirá crear instancias de las plantillas que usan la versión con constructores privados.
Este ejemplo solo permite la creación de instancias con int y float.
template<class t> class FOO { private: FOO(){}};
template<> class FOO<int>{public: FOO(){}};
template<> class FOO<float>{public: FOO(){}};
No es una forma corta y elegante de hacerlo, pero es posible.
Puedes poner un tipo de guardia en IFoo que no haga nada, asegúrate de que esté allí en T en Foo:
class IFoo
{
public:
typedef int IsDerivedFromIFoo;
};
template <typename T>
class Foo<T>
{
typedef typename T::IsDerivedFromIFoo IFooGuard;
}
Si usa C ++ 11, puede usar static_assert
con std::is_base_of
para este propósito.
Por ejemplo,
#include <type_traits>
template<typename T>
class YourClass {
YourClass() {
// Compile-time check
static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass");
// ...
}
}
Solo implícitamente.
Cualquier método que utilice en un método que realmente se llame se aplica al parámetro de la plantilla.