Я хотел бы предложить другой подход. Вместо того, чтобы создавать несколько типов списков для разных видов данных и использовать листинг или макроминализацию для применения к ним одного и того же алгоритма, создайте один общий тип списка, который делегирует поведение типа к различным функциям и присоединяет эти функции к типу списка с функцией указатели. Например:
struct generic_node {
void *data;
struct generic_node *next;
};
struct generic_list {
struct generic_node head;
int (*cmp)(void * const a, void * const b);
void *(*cpy)(void * const);
void (*del)(void *);
};
CMP указывает на функцию, которая будет возвращать -1, если * а * < Ь, 0, если * а * == Ь, и 1, если * а> * Ь, где А и В имеют были преобразованы из void * в соответствующие типы указателей. Например,
int compareInts(void * const a, void * const b)
{
int * const la = a;
int * const lb = b;
if (*a < *b) return -1;
if (*a == *b) return 0;
if (*a > *b) return 1;
}
int compareMyStruct(void * const a, void * const b)
{
struct myStruct * const la = a;
struct myStruct * const lb = b;
if (la->foo < lb->foo && strcmp(la->bar,lb->bar) < 0 && ...) return -1;
if (la->foo == lb->foo && strcmp(la->bar,lb->bar) == 0 && ...) return 0;
if (la->foo > lb->foo && strcmp(la->bar, lb->bar) > 0 && ...) return 1;
}
КПЮ указывает на функцию, которая делает глубокую копию входного параметра:
void *copyInt(void * const data)
{
int *theCopy = malloc(sizeof *theCopy);
*theCopy = *((int *) data);
return theCopy;
}
void *copyMyStruct(void * const data)
{
struct myStruct * const lData = data;
struct myStruct *newStruct = malloc(sizeof *newStruct);
newStruct->foo = lData->foo;
newStruct->bar = malloc(strlen(lData->bar) + 1);
strcpy(newStruct->bar, lData->bar);
...
return newStruct;
}
И, наконец, дель указывает на функцию, которая освобождает элементы данных:
void delInt(void * data)
{
free(data);
}
void delMyStruct(void * data)
{
struct myStruct * lData = data;
free(lData->bar);
...
free(lData);
}
Теперь вашим алгоритмам списка не нужно беспокоиться о поведении типа; они просто ссылаются на соответствующую функцию через указатель функции:
void listAdd(struct generic_list * const theList, void * const data)
{
struct generic_node *cur = &(theList->head);
struct generic_node *entry = malloc(sizeof *entry);
entry->data = theList->cpy(data);
while (cur->next != NULL && theList->cmp(cur->next->data, entry->data) < 0)
cur = cur->next;
entry->next = cur->next;
cur->next = entry;
}
/** */
void listClear(struct generic_list * const theList)
{
struct generic_node *cur = theList->head.next;
while (cur != NULL)
{
struct generic_node *entry = cur;
cur = cur->next;
theList->del(entry->data);
free(entry);
}
}
Не понимаю. Что такое «Т» здесь? Можете ли вы передать typedef на такой макрос? –
T будет типом узла. Вы также можете использовать расширение gcc «typeof», чтобы избежать необходимости делать это. –
Помните, что макрос - это просто замена текста. T - это только токен, который вы хотите отобразить в этой позиции в расширенном тексте. –