Pracuję nad opakowaniem interfejsu API języka C ++, który zapewnia dostęp do magazynu danych (Hazelcast) w funkcjach C, aby dostęp do magazynu danych był również możliwy z kodu tylko w języku C.
Interfejs API Hazelcast C ++ dla struktury danych mapy wygląda następująco:
auto map = hazelcastClient->client->getMap<int, string>(mapName);
map.put(key, value);
Wykorzystuje typy szablonów key
i value
parametry. Ponieważ w C nie ma dostępnych szablonów, pomyślałem o utworzeniu funkcji otoki dla każdej specjalizacji getMap<T, U>
metody. Oznacza to, że dla każdego typu C. Chociaż zdaję sobie sprawę, że istnieją signed
i unsigned
wersje typu C, jestem zadowolony z ograniczeniem API obsługuje tylko int
, double
, float
, char *
dla key
i value
.
Napisałem więc mały skrypt, który automatycznie generuje wszystkie kombinacje. Wyeksportowane funkcje wyglądają następująco:
int Hazelcast_Map_put_int_string(
Hazelcast_Client_t *hazelcastClient,
const char *mapName,
int key,
char *value,
char** errptr
);
int Hazelcast_Map_put_int_int(
Hazelcast_Client_t *hazelcastClient,
const char *mapName,
int key,
int value,
char** errptr
);
...
Generowanie funkcję get
, set
, contains
ze wszystkich możliwych kombinacji key
i value
typów zwiększa ilość kodu sporo i choć myślę generowania kodu jest dobrym pomysłem, to dodaje dodatkową złożoność konieczności tworzenia pewnego rodzaju infrastruktury do generowania kodu.
Innym pomysłem, jaki mogę sobie wyobrazić, jest jedna ogólna funkcja w C, taka jak ta:
int Hazelcast_Map_put(
Hazelcast_Client_t *hazelcastClient,
const char *mapName,
const void *key,
API_TYPE key_type,
const void *value,
API_TYPE value_type,
char** errptr
);
Które można wykorzystać w ten sposób:
Hazelcast_Map_put(client, mapName, "key", API_TYPE_STR, "val", API_TYPE_STR, &err);
To sprawia, że jest to trochę łatwiejsze dla wywołującego, ponieważ przenosi ciężar uzyskania poprawnej specjalizacji na mój kod, ale traci bezpieczeństwo typu i wymaga rzutowania. Ponadto, do przekazywania int, jak void *
jest teraz typ key
i value
, obsada podobna (void *) (intptr_t) intVal
byłaby potrzebna po stronie wywołującej, co znowu nie jest super miłe do przeczytania i utrzymania.
- Czy jest jakaś trzecia opcja, której nie mogę rozpoznać?
- Która wersja byłaby preferowana przez programistów C?
Najczęściej jestem skłonny do automatycznego generowania wszystkich kombinacji typów i tworzenia funkcji dla każdej, chociaż plik nagłówka stanie się dość duży.