Что должен генерировать #__VA_ARGS__, когда нет переданных аргументов?
Пример кода:
#define FOO(...) You passed: #__VA_ARGS__
FOO(1,2,3)
FOO()
Предварительная обработка с Visual C++ (версия 14 CTP), получить:
You passed: "1,2,3"
You passed:
В последней строке #__VA_ARGS__
превращается в ничто. Я бы предпочел, чтобы оно превратилось в "".
Есть ли точная ссылка на то, что должно произойти? Я много гуглил, но не смог найти.
Любой предложенный обходной путь также будет полезен.
2 ответа
Согласно 6.10.3.2. Оператор # (C11):
Семантика
2 - [...] Строковый литерал, соответствующий пустому аргументу:
""
, [...]
Так что я думаю, что MSVC здесь не так.
Я бы обошел это, используя конкатенацию строковых литералов:
#define FOO(...) You passed: "" #__VA_ARGS__
Параграф в стандарте (ISO14882:2011(e)) немного длинен, но довольно ясен:
16.3.2. Оператор #
2 Символьный строковый литерал - это строковый литерал без префикса. Если в списке замены параметру сразу предшествует # токен предварительной обработки, оба заменяются токеном предварительной обработки литерала строки из одной строки, который содержит написание последовательности токена предварительной обработки для соответствующего аргумента. Каждое вхождение пробела между токенами предварительной обработки аргумента становится одним пробелом в символьном строковом литерале. Пробелы перед первым токеном предварительной обработки и после последнего токена предварительной обработки, содержащего аргумент, удаляются. В противном случае исходное написание каждого токена предварительной обработки в аргументе сохраняется в строковом литерале символов, за исключением специальной обработки для создания правописания строковых литералов и литералов символов: символы \ вставляются перед каждым символом "и \" символа литерала. или строковый литерал (включая разделительные символы). Если полученная замена не является допустимым символьным строковым литералом, поведение не определено. Строковый литерал, соответствующий пустому аргументу, равен "". Порядок вычисления операторов # и ## не указан.
И с тех пор
16.3.1 Замена аргумента
2 идентификатор
__VA_ARGS__
то, что происходит в списке замены, должно рассматриваться как параметр, а переменные аргументы должны формировать токены предварительной обработки, используемые для его замены.
это то же самое для varags, как и для обычных параметров.