En general, no es necesario restringir con qué tipos de plantillas se pueden crear instancias. O bien la plantilla es compilable con el tipo dado (y funciona bien) o no (y produce un error de compilación sin ningún esfuerzo por parte del programador).
Si usted necesita para poner en restricciones, en general, los tipos tienen algo en común que puede ser descrito por algunos rasgos de tipo que ya están disponibles (biblioteca estándar, 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 enteros, usando std::numeric_limits
para verificarla (si escribe su propio tipo numérico, puede especializarlo para que también funcione con su nuevo tipo entero). static_assert
es C++ 0x solamente, si no está disponible use BOOST_STATIC_ASSERT
o algún otro truco.
#include <limits>
#include <string>
template <class T>
class X
{
static_assert(std::numeric_limits<T>::is_integer, "X can be only instantiated with integer types");
//...
};
int main()
{
X<int> xi;
X<char> xc;
//X<double> xd;
//X<std::string> xs;
}
Si usted sólo va a apoyar a un puñado de tipos arbitrarios que no tienen nada en común (como se desprende de su ejemplo hipotético), una forma es emplear TypeListas. Nuevamente, aumentar la tarea puede hacer que la tarea sea mucho más fácil, pero así es cómo puede hacer la suya (esto solo va a la mitad, se requerirá trabajo adicional para hacer que la lista de tipos sea más bonita).
struct no_type {};
template <class T, class U = no_type>
struct t_list
{
typedef T head;
typedef U tail;
};
//trait to check if two types are identical
template <class T, class U>
struct is_same
{
static const bool value = false;
};
template <class T>
struct is_same<T, T>
{
static const bool value = true;
};
//compile-time recursion to check if T matches any type in list L
template <class T, class L>
struct in_type_list
{
static const bool value =
is_same<T, typename L::head>::value || in_type_list<T, typename L::tail>::value;
};
//terminates recursion
template <class T>
struct in_type_list<T, no_type>
{
static const bool value = false;
};
template <class T>
class X
{
typedef t_list<double, t_list<int, t_list<char> > > allowed_types; //double, int, char
//poor man's static_assert
typedef int check_type [in_type_list<T, allowed_types>::value ? 1 : -1];
//...
};
int main()
{
X<char> xc;
X<int> xi;
X<double> xd;
//X<float> xf;
}
Tengo curiosidad, la caja tiene usted para prohibir alguna instanciación de la plantilla de qué sirve? No puedo entender por qué no me gustaría que mi código sea reutilizado: -/ – Seb
¿Qué significa "puede variar"? ¿Pueden variar en el momento de la compilación o simplemente ser diferentes que en el ejemplo? – foraidt
@Seb: es posible que la plantilla no funcione correctamente con ciertos tipos. Puede no compilarse (en cuyo caso puede ser deseable un mensaje de error más limpio que el compilador que genere), o puede compilar pero no tiene la semántica deseada (en cuyo caso es bueno evitar que se compile) – jalf