Как создать макрос с различным поведением в зависимости от количества параметров? - PullRequest
1 голос
/ 03 апреля 2019

Я хочу создать один макрос, который будет работать по-разному, если у него есть параметры или НЕТ.

Например: есть две разные реализации ошибки печати:

// 1. Print message = check code
#define PRINT_IF(wasError) \
    do { if (wasError) printf(#wasError); } while(false)

// 2. Throws an exception with formatted message
#define PRINT_TEXT_IF(wasError, format, ...) \
    do { if (wasError) printf(format, ##__VA_ARGS__); } while(false)

И я хотел бы иметь один макрос для обоих случаев.

Я попытался создать глобальный макрос, который проверяет, имеет ли он параметр или нет, на основе подхода из Как посчитать количество аргументов, переданных функции, которая принимает переменное число аргументов? .

#define RANDOM_GUID "5c300a82-2fe8-4bd3-ad12-ef13fa7b4a82"
#define FIRST_ARG(a1, ...) a1
#define HAS_ARGS(...) FIRST_ARG(##__VA_ARGS__, RANDOM_GUID)

#define GLOBAL_PRINT_IF(wasError, ...)             \
    do {                                           \ 
      if (wasError) {                              \
        if (HAS_ARGS(##__VA_ARGS__)==RANDOM_GUID ) \
          PRINT_IF(wasError);                      \
        else                                       \
          PRINT_TEXT_IF(wasError, __VA_ARGS__);    \
      }                                            \
    } while(false)

Я предполагаю, что, поскольку FIRST_ARG всегда возвращает первый аргумент, он вернет RANDOM_GUID, если ##__VA_ARGS__ пусто.

Но этот код не компилируется с ошибкой : вставка "." и «красный» не дает действительный токен предварительной обработки . Я пытался поиграть с ## до __VA_ARGS__, но не получилось с expected primary-expression before ‘==’ token в очереди

if (HAS_ARGS(__VA_ARGS__)==RANDOM_GUID )

Итак, что я делаю не так? Как правильно с этим бороться?

1 Ответ

1 голос
/ 03 апреля 2019
  1. Начните с того, как получить номер аргумента в вариационном макросе здесь
  2. Затем, когда вы узнаете, как получить номер аргумента, вы можете легко проверить, является ли это число 0 .

И этот фрагмент возвращает номер аргумента события, если это 0:

#include <stdio.h>

#define PRINT(...)  (printf("%d\n", sizeof((int[]){__VA_ARGS__})/sizeof(int)))

int main(void)
{
    PRINT();
    PRINT(1,1);
    PRINT(1,1,1,1);
    return 0;
}

таклегко, этот второй фрагмент делает работу

#include <stdio.h>

#define PRINT(...)  (((sizeof((int[]){__VA_ARGS__})/sizeof(int))==0)?printf("do A\n"):printf("do B\n"))

int main(void)
{
    PRINT();
    PRINT(1,1);
    PRINT(1,1,1,1);
    return 0;
}
...