Подсчет аргументов в макросе - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь понять подсчет аргументов в макросе предварительной обработки C и идею этого ответа . У нас есть следующий макрос (я изменил количество аргументов для простоты):

#define HAS_ARGS(...) HAS_ARGS_(__VA_ARGS__, 1, 1, 0,)
#define HAS_ARGS_(a, b, c, N, ...) N

Насколько я понимаю, цель этого макроса состоит в том, чтобы проверить, пустые ли varargs. Таким образом, в пустых varargs вызов макроса заменяется на 0, что кажется нормальным. Но с одним аргументом он также превращается в 0, что мне кажется странным.

HAS_ARGS(); //0
HAS_ARGS(123); //also 0
HAS_ARGS(1, 2); //1

LIVE DEMO

Кажется, я понимаю причину. В случае пустых varargs a заменяется пустым токеном предварительной обработки, в случае одного аргумента vararg a заменяется аргументом, дающим тот же результат.

Есть ли способ получить 0, возвращаемый в случае, если переменные varargs пусты, 1 в случае, если номер аргумента от 1 до определенного в HAS_ARGS_ вызова макроса без использования запятой или других несоответствующих приемов. Я имею в виду

SOME_MACRO_F() //0
SOME_MACRO_F(234) //1
SOME_MACRO_F(123, 132) //1
//etc

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Кажется трудным вычислить это во время компиляции, но вы можете сделать это во время выполнения, приведя в соответствие аргументы и проверив, пуста ли строка.

Протестировано с gcc:

#include <stdio.h>
#define HAS_ARGS(...) (#__VA_ARGS__[0] != '\0')

int main()
{
   printf("%d %d %d %d\n",HAS_ARGS(),HAS_ARGS(10),HAS_ARGS(20,"foo"),HAS_ARGS(10,20));
    return 0;
}

это печатает:

0 1 1 1

негласно, вот что выводит препроцессор:

int main()
{
   printf("%d %d %d %d\n",(("")[0] != '\0'),(("10")[0] != '\0'),(("20,\"foo\"")[
0] != '\0'),(("10,20")[0] != '\0'));
    return 0;
}
0 голосов
/ 14 января 2019

Нельзя передать нулевые аргументы HAS_ARGS(...). ISO C (и C ++, по крайней мере, в течение следующих двух лет) требует, чтобы многоточие соответствовало по крайней мере одному дополнительному аргументу после последнего именованного.

Если именованных нет, то макросу необходимо передать хотя бы один аргумент. В случае HAS_ARGS() дополнительный аргумент является просто пустой последовательностью токена. Ноль аргументов просто невозможна.

Это именно тот случай использования в ответе. Целевой макрос ожидает хотя бы один аргумент. Таким образом, мы можем использовать оболочку, принимающую только многоточие для «разрешения перегрузки». Лучшее имя, вероятно, было бы HAS_MORE_THAN_1_ARGS. Потому что это то, что предикат должен вам сказать. Увы, я одобрил краткость этого ответа.

...