2012-02-16 10 views
7

Comienzo a disculparme si soy tan estúpido como para no encontrar la respuesta si es tan obvio.C++: ¿Cómo evitar que la plantilla especialice un puntero?

He visto docenas de páginas que hablan de tener una especialización de plantilla específica para los parámetros del puntero.

Me gustaría poder evitar que una plantilla especialice los parámetros del puntero, pero no puedo encontrar la manera de hacerlo.

template< class T > 
void function(T arg) 
{ 
    //... 
} 

int main() 
{ 
    int i = 42; 

    function(i); // Ok 
    function(&i); // Die bastart with a compiler error! 
} 

¿Es posible?

Gracias.

+1

Cuando tiene acceso a C++ 11, puede usar static_assert – PlasmaHH

+1

¿No debería ser 'template '? – Jacob

+0

@Jacob: corregido ahora. – MSalters

Respuesta

14

Se puede declarar la especialización (en este caso es técnicamente sólo una sobrecarga) pero no definirlo :)

template<typename T > 
void function(T arg) 
{ 
//... 
} 

template<typename T > 
void function(T* arg); //no definition 

int main() 
{ 
    int i = 42; 
    function(i); // Ok 
    function(&i); //ERROR 
} 
+0

¿Es esto un error de engarce o un error de compilación? –

+4

@ daknøk: Es un error del compilador, porque es una plantilla. La definición de la plantilla debe estar en la misma unidad de traducción (archivo fuente). El vinculador no sabe nada sobre plantillas. El compilador es responsable de la creación de instancias de la plantilla, y no puede hacerlo sin la definición –

+0

+1 Hah, por supuesto, ¡así de fácil! ¿Por qué siempre quiero hacerlo de la manera difícil? –

6

soy yo un novato plantilla metaprogramming, pero creo

template<typename T> 
void function(typename std::enable_if<!std::is_pointer<T>::value,T>::type arg) 
{ 
    //... 
} 

debería funcionar, ya que esta función solo debería existir para parámetros que no sean de puntero. Por supuesto, esto requiere C++ 11 o al menos TR1 o características de rasgos de tipo boost.

+0

+1 Estaba probando una alternativa (a la que estoy un poco más acostumbrado): 'template typename enable_if :: value> :: type function (T arg)', pero la tuya también debería funcionar. (Y ambos desencadenan * errores de compilador *, en lugar de errores de enlazador) –

7

En C++ 11, puede utilizar static_assert de una manera como esto:

template<class T> 
void func(T arg) { 
    static_assert(!std::is_pointer<T>::value, 
       "The argument to func must not be a pointer."); 
    // Do something after the static_assert. 
    // Now you are sure that T isn't a pointer. 
} 

Un ejemplo se puede encontrar here on Ideone.

Lo recomiendo porque dará más mensajes de error útiles cuando alguien intente llamar a su función con un puntero (los errores del enlazador pueden ser muy confusos en este caso). Además, los errores del vinculador no se mostrarán antes de que se produzca la vinculación.

Cuestiones relacionadas