Ошибка ВК? Компилятор не может подсчитать аргументы __VA_ARGS__

Microsoft Visual Studio Professional 2015 версии 14.0.25431.01, обновление 3 выдает ошибки при компиляции приведенного ниже кода. Похоже на ошибку для меня.


Спасибо.

#include <iostream>

#define A( a, b, c, ... ) #__VA_ARGS__
#define B( ... ) A(__VA_ARGS__)

int main()
{
  // warning C4003: not enough actual parameters for macro 'A'
  // error C2059: syntax error: ';'
  std::cout << B( 1, 2, 3, 4 ); // should print '4'                                    
  return 0;
}

person zdf    schedule 28.12.2016    source источник
comment
MSVC неправильно расширяет __VA_ARGS__   -  person cpplearner    schedule 28.12.2016
comment
@cpplearner Спасибо.   -  person zdf    schedule 28.12.2016


Ответы (1)


Мне это тоже кажется багом. Это можно обойти с помощью другого слоя макросов:

#define EXPAND(...) __VA_ARGS__
#define A( a, b, c, ... ) #__VA_ARGS__
#define B( ... ) EXPAND(EXPAND(A) (__VA_ARGS__))

Идея состоит в том, что сначала EXPAND(A) расширяется до A, а (__VA_ARGS__) расширяется до ( 1, 2, 3, 4 ). Затем у вас остается A ( 1, 2, 3, 4 ), который VC++ понимает, если вы снова принудительно расширите его.

person Community    schedule 28.12.2016
comment
Я думаю, #define EXPAND( a ) a и #define B( ... ) EXPAND(A(__VA_ARGS__)) проще. - person zdf; 28.12.2016
comment
@ZDF Вам нужны ... и __VA_ARGS__ для EXPAND, если вы хотите передать что-либо, содержащее запятые. Что касается EXPAND(A(__VA_ARGS__)), то все равно следует сначала попытаться расширить A(__VA_ARGS__), а затем снова расширить результат. Если этого достаточно, чтобы подавить предупреждение, я думаю, вы нашли еще одну ошибку, и если эта ошибка будет исправлена ​​раньше, чем исходная, код снова сломается. - person ; 28.12.2016
comment
Я думаю, что я не нашел вещь. :) По словам Microsoft, поведение правильное. См. ссылку, предоставленную cpplearner. - person zdf; 28.12.2016
comment
@ZDF Microsoft ошибается в этом. Они для удобства игнорируют [cpp.subst]p2. Идентификатор __VA_ARGS__, встречающийся в списке замены, должен рассматриваться как параметр, а переменные аргументы должны формировать токены предварительной обработки, используемые для его замены. Обратите внимание, как если бы это был параметр. Замена параметров происходит до определения макроса, которое снова расширяется, и содержащиеся в нем запятые могут использоваться в качестве разделителей аргументов макроса. - person ; 28.12.2016
comment
Я заполнил форму об ошибке в Microsoft Connect, но сомневаюсь, что они что-то изменят. Это будет не в первый раз. Спасибо. - person zdf; 28.12.2016