Tipo de fuerza de plantilla de C ++

Tengo una clase de plantilla básica, pero me gustaría limitar el tipo de especialización a un conjunto de clases o tipos. p.ej:

template  class MyClass { .../... private: T* _p; }; MyClass a; // OK MYCLass b; // OK MyClass c; // not OK 

Esos son solo ejemplos, los tipos permitidos pueden variar.

¿Es eso posible? Si es así, ¿cómo hacerlo?

Gracias.

Otra versión es dejarlo indefinido para los tipos prohibidos.

 template struct Allowed; // undefined for bad types! template<> struct Allowed { }; template<> struct Allowed { }; template struct MyClass : private Allowed { // ... }; MyClass m; // nono 

Sólo una idea rápida, estoy seguro de que hay mejores enfoques:

 template  struct protector { static const int result = 1; }; template <> struct protector { static const int result = -1; }; template  class MyClass { private: char isfine[protector::result]; }; 

Sin embargo, podría ser mejor poner un comentario grueso sobre su código para evitar que los usuarios creen instancias con los tipos incorrectos 🙂

Eche un vistazo a la biblioteca de Boost Concept Check: http://www.boost.org/doc/libs/1_42_0/libs/concept_check/concept_check.htm

En general, no es necesario restringir con qué tipos de plantillas se pueden crear instancias. O la plantilla es comstackble con el tipo dado (y funciona bien) o no (y produce un error de comstackción sin ningún esfuerzo por parte del progtwigdor).


Si necesita poner restricciones, generalmente los tipos tienen algo en común que algunos rasgos de tipo que ya están disponibles (biblioteca estándar, boost::type_traits ) pueden boost::type_traits , o puede crear un nuevo rasgo de tipo para ellos.

Por ejemplo, aquí hay una clase de plantilla que solo permite tipos de enteros, usando std::numeric_limits para verificarla (si escribe su propio tipo numérico, puede especializarse para que también funcione con su nuevo tipo de entero). static_assert es solo C ++ 0x, si no está disponible, use BOOST_STATIC_ASSERT o algún otro truco.

 #include  #include  template  class X { static_assert(std::numeric_limits::is_integer, "X can be only instantiated with integer types"); //... }; int main() { X xi; X xc; //X xd; //X xs; } 

Si solo planea admitir un puñado de tipos arbitrarios con nada en común (como se desprende de su ejemplo hipotético), una forma es emplear listas de tipos. Una vez más, boost puede hacer que la tarea sea mucho más fácil, pero aquí es cómo puede hacer su propio trabajo (esto solo va a la mitad, se requeriría un trabajo adicional para que la statement de la lista de tipos sea más bonita).

 struct no_type {}; template  struct t_list { typedef T head; typedef U tail; }; //trait to check if two types are identical template  struct is_same { static const bool value = false; }; template  struct is_same { static const bool value = true; }; //compile-time recursion to check if T matches any type in list L template  struct in_type_list { static const bool value = is_same::value || in_type_list::value; }; //terminates recursion template  struct in_type_list { static const bool value = false; }; template  class X { typedef t_list > > allowed_types; //double, int, char //poor man's static_assert typedef int check_type [in_type_list::value ? 1 : -1]; //... }; int main() { X xc; X xi; X xd; //X xf; } 

Hay varios trucos que permiten verificar algunas cosas, dependiendo de cuáles sean sus criterios para la creación de instancias o no. En la práctica, debe usar una biblioteca de palanca superior para aquellos como Boost’s Concept Check.

No estoy seguro de esto, pero podría agregar otra especialización de plantilla para la plantilla doble

 class MyClass { .../... private: T* _p; }; template  class MyClass {}; 

lo que funcionaría para su ejemplo, pero no para el caso general.

En general, agregaría una aserción de comstackción para verificar tipos no deseados.

Espero eso ayude.