2010-05-20 15 views
12

W kodzie, który piszę, potrzebuję funkcji foo(int, char*) i foo(int, int).Czy istnieje odpowiednik w C dla szablonów C++?

Jeśli kodowałem to w C++, używałbym szablonów. Czy istnieje odpowiednik C? Czy powinienem używać wskaźników void? W jaki sposób?

+7

Czasami można również użyć makr do emulowania zachowania szablonu. – Lucas

+2

W C++ używałbyś przesłonięcia nie szablonów dla tego przeciążenia – Motti

+4

@Motti, nieprawdaż? – Amarghosh

Odpowiedz

13

Nie możesz tego zrobić.
W C nie ma przeciążeń, jedna funkcja, jedno imię, musisz użyć typu, który obsługuje wszystkie twoje potrzeby, np. (Void *)

Albo to, albo zrobić foo_int(int,int) i foo_char(int, char*)

+3

Zgadzam się. Zwykłe rozwiązanie C składa się z nazw funkcji z przyrostkami typu. słynny przykład: atoi, atol, atoll (IIRC) i OpenGL glVector3f, glVector2f, glColor3f, ... – dbemerlin

+0

, ale jeśli używam void * jak mogę sprawdzić, jaki typ danych jest? nie ma c isInteger i isCharPointer, prawda? – nunos

+1

Nie możesz. Jeśli nie wiesz, co to jest wcześniej, musisz podać inny parametr, aby go rozróżnić. Ale to brzydkie, zaimplementowałem 'foo_int' i' foo_char' –

23

myślę najbliżej można dostać w C do szablonów jest jakiś brzydki kod makro. Na przykład, aby zdefiniować prostą funkcję, która zwraca dwa razy swój argument:

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

MAKE_DOUBLER(int) 
MAKE_DOUBLER(float) 

Zauważ, że C nie ma przeciążania funkcji, trzeba grać sztuczki z nazwą funkcji (Powyższe sprawia, że ​​zarówno doubler_int i doubler_float, a będziesz musiał do nich zadzwonić w ten sposób).

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

Na marginesie, programista, który podąża za tobą (który może być tobą), nie * doceni tej techniki. Jeśli widzisz wywołanie 'doubler_int()' i nie wiesz o makrze, w jaki sposób znajdziesz tę funkcję? Wyszukiwanie kodu źródłowego go nie odnajdzie. –

+0

Gdzie można pisać MAKE_DOUBLER (int) i MAKE_DOUBLER (float)? –

+0

@ShehbazJaffer Gdziekolwiek zwykle deklarujesz funkcję. –

5

Inni omawiali wewnętrzne ograniczenie c w odniesieniu do przeciążenia. Należy jednak pamiętać, że jeśli można wywnioskować tym przypadku jest potrzebna można użyć varargs:

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

Jeśli nie można wywnioskować, możesz przekazać dodatkowy argument:

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

gdzie spec mówi funkcja, której należy oczekiwać w kolejnych argumentach. Podobnie jak rodziny funkcji printf i scanf. W rzeczywistości wygodne może okazać się ponowne użycie konwencji printf/scanf w celu określenia typu, co pozwoli zaoszczędzić na użytkownikach, którzy muszą pochylić się w innym języku.

6

Tak, jest. Można użyć wyrażenia typu-generic w 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

Zamiast void * można również użyć do unii do przechowywania wszelkiego rodzaju danych, czego potrzebujesz:

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); 
} 

oczywiście, należy utworzyć stałe dla wartości typu.

0

Szablony można zrealizować za pomocą nagłówków szablonów.

Let Foo.h tak:

#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 

Aby go użyć można zrobić:

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

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

Teraz masz pchar_foo() i int_foo() których można użyć.

Zaletą tego jest to, że jeśli występuje problem z kompilacją, w nagłówku szablonu pojawia się numer wiersza, a nie kompilator, który twierdzi, że makro jest niepoprawne, a kodowanie działa również w niektórych środowiskach IDE.

Makra są bardzo popularne, więc wyodrębniłem ich definicję do osobnego nagłówka, a ich niezdefiniowanie do innego.

Zaimplementowałem części STL przy użyciu tego wzoru dla zabawy i używam go w niektórych moich projektach C.

Powiązane problemy