Я реализую набор общих, но не столь тривиальных (или подверженных ошибкам) структур данных для C (здесь) и только что пришел с идеей, которая заставила меня задуматься.
Короче говоря, что является лучшим способом реализовать две структуры, которые используют похожие алгоритмы, но имеют разные интерфейсы, не имея необходимости копировать/вставлять/переписывать алгоритм?. В лучшем случае, я имею в виду большинство поддерживаемых и отлаживаемых.
Я думаю, что очевидно, почему вы не хотели бы иметь две копии одного и того же алгоритма.
Мотивация
Скажите, что у вас есть структура (назовите ее map) с набором связанных функций (map_*()). Так как карта должна отображать что угодно, мы обычно реализуем ее с помощью void *key и void *data. Однако подумайте о карте от int до int. В этом случае вам нужно будет хранить все ключи и данные в другом массиве и указывать их адреса на map, что не так удобно.
Теперь представьте, была ли подобная структура (назовите ее mapc, c для "копий" ), которая во время инициализации принимает sizeof(your_key_type) и sizeof(your_data_type) и задана void *key и void *data при вставке, она будет использовать memcpy, чтобы скопировать ключи и данные на карте, а не просто удерживать указатели. Пример использования:
int i;
mapc m;
mapc_init(&m, sizeof(int), sizeof(int));
for (i = 0; i < n; ++i)
{
    int j = rand();  /* whatever */
    mapc_insert(&m, &i, &j);
}
 что довольно приятно, потому что мне не нужно сохранять еще один массив из i и j s.
Мои идеи
В приведенном выше примере map и mapc очень тесно связаны. Если вы думаете об этом, структуры и функции map и set также очень похожи. Я подумал о следующих способах реализации их алгоритма только один раз и использовать его для всех из них. Однако ни один из них не удовлетворяет меня.
-  Использовать макросы. Напишите код функции в файле заголовка, оставив зависимые от структуры элементы как макросы. Для каждой структуры определите правильные макросы и включите файл: map_generic.h #define INSERT(x) x##_insert int INSERT(NAME)(NAME *m, PARAMS) { // create node ASSIGN_KEY_AND_DATA(node) // get m->root // add to tree starting from root // rebalance from node to root // etc } map.c #define NAME map #define PARAMS void *key, void *data #define ASSIGN_KEY_AND_DATA(node) \ do {\ node->key = key;\ node->data = data;\ } while (0) #include "map_generic.h" mapc.c #define NAME mapc #define PARAMS void *key, void *data #define ASSIGN_KEY_AND_DATA(node) \ do {\ memcpy(node->key, key, m->key_size);\ memcpy(node->data, data, m->data_size);\ } while (0) #include "map_generic.h"Этот метод не слишком плох, но он не настолько изящный. 
-  Используйте указатели на функции. Для каждой части, которая зависит от структуры, передайте указатель на функцию. map_generic.c int map_generic_insert(void *m, void *key, void *data, void (*assign_key_and_data)(void *, void *, void *, void *), void (*get_root)(void *)) { // create node assign_key_and_data(m, node, key, data); root = get_root(m); // add to tree starting from root // rebalance from node to root // etc } map.c static void assign_key_and_data(void *m, void *node, void *key, void *data) { map_node *n = node; n->key = key; n->data = data; } static map_node *get_root(void *m) { return ((map *)m)->root; } int map_insert(map *m, void *key, void *data) { map_generic_insert(m, key, data, assign_key_and_data, get_root); } mapc.c static void assign_key_and_data(void *m, void *node, void *key, void *data) { map_node *n = node; map_c *mc = m; memcpy(n->key, key, mc->key_size); memcpy(n->data, data, mc->data_size); } static map_node *get_root(void *m) { return ((mapc *)m)->root; } int mapc_insert(mapc *m, void *key, void *data) { map_generic_insert(m, key, data, assign_key_and_data, get_root); }Этот метод требует записи большего количества функций, которые можно было бы избежать в методе макросов (как вы можете видеть, код здесь длиннее) и не позволяет оптимизаторам встроить функции (поскольку они не видны для map_generic.cфайл).
Итак, как бы вы начали реализовывать что-то вроде этого?
Примечание. Я написал код в форме вопроса о переполнении стека, поэтому извините меня, если есть незначительные ошибки.
Боковой вопрос: у кого-то есть лучшая идея для суффикса, который говорит, что "эта структура копирует данные вместо указателя"? Я использую c, который говорит "копии", но на английском может быть гораздо лучшее слово, о котором я не знаю.
Обновление:
У меня появилось третье решение. В этом решении записывается только одна версия map, которая хранит копию данных (mapc). Эта версия использовала бы memcpy для копирования данных. Другой map является интерфейсом к этому, принимая указатели void *key и void *data и отправляя &key и &data в mapc так, чтобы адрес, который они содержат, был скопирован (используя memcpy).
Это решение имеет недостаток, что нормальное назначение указателя выполняется memcpy, но оно полностью решает проблему в противном случае и очень чистое.
В качестве альтернативы можно реализовать только map и использовать дополнительный vectorc с mapc, который сначала копирует данные в вектор, а затем передает адрес map. Это имеет побочный эффект, что удаление из mapc будет либо значительно медленнее, либо оставить мусор (или потребовать от других структур повторного использования мусора).
Обновление 2:
Я пришел к выводу, что неосторожные пользователи могут использовать мою библиотеку так, как они пишут С++, копировать после копирования после копирования. Поэтому я отказываюсь от этой идеи и принимаю только указатели.
