Почему макрос с переменным значением дает мне ошибку? - PullRequest
0 голосов
/ 02 октября 2018

Учитывая этот пример кода:

#define vX(a, ...) ((a)(__VA_ARGS__) ? 1 : 0)

{
    int f();
    vX(f);
}

Я получаю error C2155: '?': invalid left operand, expected arithmetic or pointer type

С другой стороны, если я предоставлю второй аргумент макросу, он компилирует fin - например ::

vX(f,1)

в порядке.Я компилирую код C с помощью компилятора msvc.

Извините, что беспокою всех, но ошибка была на моей стороне - две функции, которые выдавали ошибку, не только не имели аргументов, но также имели тип возвращаемого значения void -это было причиной моей проблемы, а не макросов.

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

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

Причина в том, что количество аргументов в значительной степени определяется количеством запятых в макросе.Так, например, vX(f,) может привести к исчезновению вашей ошибки.Причина заключается в том, что мы снова предоставляем два аргумента, а именно f и пустую последовательность токенов после запятой.

Один из способов обойти это - разделить макрос на два расширения:

#define vX_(a, ...) ((a)(__VA_ARGS__) ? 1 : 0)
#define vX(...) vX_(__VA_ARGS__,)

Обратите внимание, как я добавил эту запятую?Теперь, когда вы напишите vX(f), он расширится до vX_(f,), который снова расширится, чтобы дать вам желаемое выражение.Хотя, в общем случае это не сработает, так как вы получите запятую в конце.Вот почему GCC ввел __VA_OPT__ ( @ unwind's answer ), чтобы запятую можно было добавить условно.

0 голосов
/ 02 октября 2018

Из документации GCC :

Когда вызывается макрос, все токены в его списке аргументов после последнего именованного аргумента (у этого макроса нет ни одного), включая любыезапятые, стать переменным аргументом.Эта последовательность токенов заменяет идентификатор __VA_ARGS__ в теле макроса, где бы он ни появлялся.

Таким образом, в основном часть __VA_ARGS__ не может быть пустой, для которой требуются расширения GNU (__VA_OPT__).

...