2011-04-22 6 views
10

Me gustaría definir una función de plantilla pero no permitir la creación de instancias con un tipo particular. Tenga en cuenta que, en general, todos los tipos están permitidos y la plantilla genérica funciona, solo quiero prohibir el uso de algunos tipos específicos.No permitir una instancia de plantilla de función específica

Por ejemplo, en el siguiente código deseo evitar el uso de double con la plantilla. Esto en realidad no evita la creación de instancias, solo causa un error de enlazador al no tener la función definida.

template<typename T> 
T convert(char const * in) 
{ return T(); } 

//this way creates a linker error 
template<> 
double convert<double>(char const * in); 

int main() 
{ 
    char const * str = "1234"; 

    int a = convert<int>(str); 
    double b = convert<double>(str); 
} 

El código es sólo una demostración, obviamente, la función de conversión debe hacer algo más.

Pregunta: En el código anterior, ¿cómo puedo producir un error de compilación al intentar utilizar la creación de instancias convert<double>?


La pregunta relacionada más cercano que puedo encontrar es How to intentionally cause a compile-time error on template instantiation Se trata de una clase, no una función.

La razón por la que necesito hacer esto es porque los tipos que deseo bloquear realmente compilarán y harán algo con la versión genérica. Sin embargo, se supone que no es parte del contrato de la función y puede no ser compatible con todas las plataformas/compiladores y en versiones futuras. Por lo tanto, me gustaría evitar que se use en absoluto.

+0

Usted ya ha hecho eso, ¿verdad? – Nawaz

+0

No, eso da un error del enlazador sobre una función faltante. Ese error tampoco le dirá dónde está el problema, simplemente le indicará en qué módulo se encuentra. –

+3

Podría desencadenar un error en tiempo de compilación utilizando 'static_assert':' template <> foo (const char *) {static_assert (false, "no permitido"); } ' – evnu

Respuesta

3

me gustaría utilizar una aserción estática dentro de su llamada a la función para crear el fracaso adecuada durante la instanciación función:

template<typename T> 
class is_double{ static const int value = false; } 

template<> 
class is_double<double>{ static const int value = true; } 

template<typename T> 
T convert(const char *argument){ 
    BOOST_STATIC_ASSERT(!is_double<T>::value); 
    //rest of code 
} 

Y eso debería funcionar dentro de una función.

+0

Debe ser' static bool const value'. :) – Xeo

+0

@Xeo gracias, corregido. – wheaties

+0

Ah sí. Me siento tonto ya que uso la afirmación estática en muchos lugares, de alguna manera simplemente escapé de mi mente aquí. –

1

Se puede usar un funtor en lugar de una función:

template<typename T> 
struct convert { 
    T operator()(char const * in) const { return T(); } 
}; 
template<> struct convert<double>; 

int main() 
{ 
    char const * str = "1234"; 

    int a = convert<int>()(str); 
    double b = convert<double>()(str); // error in this line 

    return 0; 
} 

Esto le dará un error en el punto de ejemplificación.

Mediante la adición de función auxiliar obtendrá lo que se desea:

template<typename T> 
struct convert_helper { 
    T operator()(char const * in) const { return T(); } 
}; 
template<> struct convert_helper<double>; 

template<typename T> 
T convert(char const * in) { return convert_helper<T>()(in); } 

int main() 
{ 
    char const * str = "1234"; 

    int a = convert<int>(str); 
    double b = convert<double>(str); 

    return 0; 
} 
+0

Esta es también una buena opción ya que ya tengo esencialmente el segundo esquema por otras razones. –

1

Si no quiere depender de static_assert o hacer que el código portable pre-C++ 0x, utilice esto:

template<class T> 
void func(){ 
    typedef char ERROR_in_the_matrix[std::is_same<T,double>::value? -1 : 1]; 
} 

int main(){ 
    func<int>(); // no error 
    func<double>(); // error: negative subscript 
} 
+0

No pensé que 'std: is_same' estaba disponible antes de C++ 11 (o C++ 0x como lo fue aquí) – Pharap

0

Considere Boost disable_if y Boost TypeTraits

Tome un vistazo a How can I write a function template for all types with a particular type trait?

Este es un ejemplo:

#include <boost/type_traits.hpp> 
#include <boost/utility/enable_if.hpp> 

template<typename T> 
T convert(char const * in, 
      typename boost::disable_if<boost::is_floating_point<T>, T>::type* = 0) 
{ return T(); } 


int main() 
{ 
    char const * str = "1234"; 

    int a = convert<int>(str); 
    double b = convert<double>(str); 
    return 0; 
} 


Este es el error de compilación para la cadena

double b = convert<double>(str); 

1>. \ Simple_no_stlport.cpp (14): error C2770: plantilla explícita no válida argumento (s) para 'T convert (const char *, boost :: disable_if, T> :: tipo *)' 1>. \ simple_no_stlport.cpp (5): vea declaración de 'convert'

Cuestiones relacionadas