2010-05-20 25 views
12

En el código que estoy escribiendo necesito las funciones foo(int, char*) y foo(int, int).¿Hay un equivalente en C para las plantillas de C++?

Si estaba codificando esto en C++ usaría plantillas. ¿Hay algún equivalente para C? ¿O debería usar punteros vacíos? ¿Cómo?

+7

A veces también puede usar macros para emular el comportamiento de la plantilla. – Lucas

+2

En C++, no se utilizarían las plantillas para esa – Motti

+4

sobrecarga de @Totti, ¿o no? – Amarghosh

Respuesta

13

No puede hacer eso.
En C no hay sobrecargas, una función, un nombre, deberá usar un tipo que admita todas sus necesidades, p. (Void *)

O eso, o hacer un foo_int(int,int) y una foo_char(int, char*)

+3

Estoy de acuerdo. La solución habitual de C consiste en nombres de funciones con sufijos de tipo. ejemplo famoso: atoi, atol, atoll (IIRC) y OpenGL glVector3f, glVector2f, glColor3f, ... – dbemerlin

+0

pero si utilizo void * ¿cómo puedo verificar qué tipo de datos son? no hay c isInteger e isCharPointer, ¿verdad? – nunos

+1

No puedes. Si no sabe con anticipación, deberá pasar otro parámetro para distinguir. Pero eso es algo feo, implementaría 'foo_int' y' foo_char' –

23

Creo que lo más cerca que puede obtener en C para las plantillas es un poco de código de macro feo. Por ejemplo, para definir una función simple que devuelve el doble de su argumento:

#define MAKE_DOUBLER(T) \ 
    T doubler_##T(T x) { \ 
     return 2 * x; \ 
    } 

MAKE_DOUBLER(int) 
MAKE_DOUBLER(float) 

Tenga en cuenta que ya que C no tiene la sobrecarga de funciones, tienes que jugar trucos con el nombre de la función (el anterior hace tanto doubler_int y doubler_float, y tendrás que llamarlos de esa manera).

printf("%d\n", doubler_int(5)); 
printf("%f\n", doubler_float(12.3)); 
+7

Como comentario adicional, el programador de mantenimiento que lo sigue (que también puede ser usted) * * no apreciará esta técnica. Si ve una llamada a 'doubler_int()' y no conoce la macro, ¿cómo encontraría esa función? Una búsqueda del código fuente no lo encontrará. –

+0

¿Dónde se escribe MAKE_DOUBLER (int) y MAKE_DOUBLER (float)? –

+0

@ShehbazJaffer En cualquier lugar que normalmente declare una función. –

5

Otros han discutido la limitación intrínseca de c con respecto a la sobrecarga. Tenga en cuenta, sin embargo, que si se puede deducir cuyo caso se necesita puede utilizar varargs:

#include <stdarg.h> 
foo(int, ...); 

Si no puede deducirlo, se puede pasar un argumento extra:

foo(int, char *spec, ...); 

donde dice spec la función qué esperar en los argumentos posteriores. Como las familias de funciones printf y scanf. De hecho, puede que le resulte conveniente reutilizar las convenciones printf/scanf para especificar el tipo, lo que le ahorrará a sus usuarios tener que utilizar otro minilenguaje.

6

Sí, lo hay. Se puede utilizar la expresión de tipo genérico en C11:

#include <stdio.h> 

void foo_char_ptr(int a, char *b) { 
    printf("Called int, char*.\n"); 
} 

void foo_int(int a, int b) { 
    printf("Called int, int.\n"); 
} 

#define foo(a, b) _Generic((b), char*: foo_char_ptr, int: foo_int)(a, b) 

int main() { 
    foo(1, 1); 
    foo(1, "foo"); 
} 

// Output: 
// Called int, int. 
// Called int, char*. 
2

En lugar de void * también se puede utilizar una unión para celebrar cualquier tipo de datos que necesita:

typedef struct { 
    int type; 
    union { 
     char* char_ptr; 
     int int_val; 
     // etc... 
    }; 
} foo_data; 

void foo(foo_data data) 
{ 
    switch (data.type) { 
     case 0: 
      printf("%s\n", data.char_ptr); 
      break; 
     case 1: 
      printf("%i\n", data.int_val); 
      break; 
    } 
} 

void main() 
{ 
    foo_data data; 

    data.type = 0; data.char_ptr = "hello"; 
    foo(data); 
    data.type = 1; data.int_val = 12; 
    foo(data); 
} 

Por supuesto, se debe crear constantes para los valores de tipo.

0

Las plantillas se pueden realizar usando encabezados de plantilla.

Let foo.h así:

#ifndef PREFIX 
    #define PREFIX 
#endif 
#define CCAT2(x, y) x ## y 
#define CCAT(x, y) CCAT2(x, y) 
#define FN(x) CCAT(PREFIX, x) 

#ifndef T 
    #error Template argument missing. 
#endif 

void FN(foo)(int x, T t) 
{ 
    // Whatever. 
} 


#undef T 
#undef PREFIX 
#undef CCAT2 
#undef CCAT 
#undef FN 

Para usarlo se puede hacer:

#define T char* 
#define PREFIX pchar_ 
#include "foo.h" 

#define T int 
#define PREFIX int_ 
#include "foo.h" 

Ahora usted tienen pchar_foo() y int_foo() que se puede utilizar.

Las ventajas de esto es que si hay un problema de compilación, obtiene el número de línea en el encabezado de la plantilla en lugar de que el compilador simplemente diga que la macro es incorrecta y la finalización del código también funciona en algunos IDE.

El PREFIX, los CCAT y FN macros son muy comunes por lo extraje su definición en una cabecera separada, y su indefinición a otro.

Implementé partes del STL usando este patrón por diversión y lo uso en algunos de mis proyectos C.

Cuestiones relacionadas