Перегрузка функции Variadic в C

После небольшого исследования и много гадости я придумал это:

#include <stdio.h>

// Variadic Function Overloading:

#define VOID    "__variadic_VOID__"

#define variadic_count(...) variadic_count_(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
#define variadic_count_(_6, _5, _4, _3, _2, _1, count, ...) count

#define variadic_token(func, ...)   variadic_token_(func, variadic_count(__VA_ARGS__))
#define variadic_token_(func, count)    variadic_token__(func, count)
#define variadic_token__(func, count)   func ## _ ## count

#define variadic(func, ...)\
do {\
    if (#__VA_ARGS__ == "\"__variadic_VOID__\"")\
    {\
        variadic_token__(func, 0)();\
    }\
    else\
    {\
        variadic_token(func, __VA_ARGS__)(__VA_ARGS__);\
    }\
} while (0)

// Usage:

#define somefunction(...)   variadic(somefunction, __VA_ARGS__)

#define somefunction_0()\
do {\
    printf("somefunction_0(VOID)\n\n");\
} while (0)

#define somefunction_1(x)\
do {\
    printf("somefunction_1(x = %i)\n\n", (x));\
} while (0)

#define somefunction_2(x, y)\
do {\
    printf("somefunction_2(x = %i, y = %i)\n\n", (x), (y));\
} while (0)

int main(int argc, char* argv[])
{
    //somefunction();   ERROR
    somefunction(VOID);
    somefunction(1);
    somefunction(11);
    somefunction(2, 3);
    //somefunction(1, 2, 3);    ERROR

    printf("\n\n");
    return 0;
}

По сути, он позволяет различать ноль и один аргумент через специальный VOID токена. Это работает, если переменной / макросу не передан строковый литерал, определенный VOID в качестве единственного аргумента. В этом случае только вызов somefunction("__variadic_VOID__"); вызовет неожиданное поведение; передача переменной с тем же значением, что и строковый литерал, не вызывает неожиданного поведения.

Хотя предоставленный код работает только для 0-6 аргументов, он может быть изменен для работы с большим количеством аргументов.

Мне любопытно, однако, относительно того, if ("blah" == "blah") {doSomething();} оптимизирован для doSomething(); по компилятору (Pelles C)? Или сравнение указателей происходит во время выполнения? Если он оптимизирован, то я думаю, что этот фрагмент кода позволяет легко и эффективно перегружать функции / макросы различными переменными... это правильно?

1 ответ

Гораздо лучшая схема для использования:

#define variadic(func, ...)\
do {\
    if (0 == *#__VA_ARGS__)\
    {\
        variadic_token__(func, 0)();\
    }\
    else\
    {\
        variadic_token(func, __VA_ARGS__)(__VA_ARGS__);\
    }\
} while (0)

Тогда звонок как somefunction() будет расширяться до вызова somefunction_0() и нет необходимости в магии VOID маркер. Это также намного безопаснее и с большей вероятностью будет оптимизировано компилятором.

Другие вопросы по тегам