MSVC не расширяет __VA_ARGS__ правильно

Рассмотрим этот код:

#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) F(__VA_ARGS__)
F(1, 2, 3)
G(1, 2, 3)

Ожидаемый вывод X = 1 and VA_ARGS = 2, 3 для обоих макросов, и то, что я получаю с GCC, однако, MSVC расширяет его следующим образом:

X = 1 and VA_ARGS = 2, 3
X = 1, 2, 3 and VA_ARGS =

То есть, __VA_ARGS__ расширяется как один аргумент, а не разбивается на несколько.

Как это обойти?

Ответ 1

Препроцессор MSVC, по-видимому, ведет себя совершенно иначе, чем стандартный спецификация.
Вероятно, следующее обходное решение поможет:

#define EXPAND( x ) x
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) EXPAND( F(__VA_ARGS__) )

Ответ 2

Я отправил следующую проблему поддержки Microsoft:

Следующая программа дает ошибку компиляции, потому что прекомпилятор неправильно отклоняет __VA_ARGS__:

#include <stdio.h>

#define A2(a1, a2) ((a1)+(a2))

#define A_VA(...) A2(__VA_ARGS__)

int main(int argc, char *argv[])
{
    printf("%d\n", A_VA(1, 2));
    return 0;
}

Препроцессор расширяет printf до:     printf ( "% d\n", ((1, 2) +()));

вместо     printf ( "% d\n", ((1) + (2)));

Я получил неудовлетворительный ответ от разработчика команды компилятора Microsoft:

Привет: компилятор Visual С++ ведет себя корректно в этом случае. Если вы комбинируете правило, что токены, которые соответствуют "..." при вызове inital macro, объединяются, чтобы сформировать единый объект (16.3/p12) с правилом, что подмакросы расширяются до замены аргумента (16.3.1/p1), то в этом случае компилятор считает, что A2 вызывается с одним аргументом: следовательно, сообщение об ошибке.

Ответ 3

Какую версию MSVC вы используете? Вам понадобится Visual С++ 2010.

__VA_ARGS__ был впервые введен C99. MSVC никогда не пытался поддерживать C99, поэтому поддержка не была добавлена.

Теперь, однако, __VA_ARGS__ включен в новый стандарт С++, С++ 2011 (ранее известный как С++ 0x), который Microsoft, по-видимому, планирует поддерживать, поэтому он поддерживается в последних версиях MSVC.

BTW, вам нужно будет использовать суффикс .cpp в исходный файл, чтобы получить эту поддержку. MSVC не обновлял свой C-интерфейс в течение длительного времени.