В конце этого ответа есть возможное решение.
Является ли это поведение ошибкой или оно проистекает из какого-то принципа?
Это вытекает из двух принципов, взаимодействие которых довольно тонкое. Поэтому я согласен, что это удивительно, но это не ошибка.
Два принципа следующие:
Внутри замены вызова макроса этот макрос не является расширен. (См. G CC Руководство, раздел 3.10.5, Само-ссылочные макросы или C Стандарт, §6.10.3.4, параграф 2.) Это исключает рекурсивное расширение макроса, которое в большинстве случаев приводит к бесконечная рекурсия, если это разрешено. Хотя, вероятно, никто не ожидал такого использования, оказывается, что были бы способы использования рекурсивного расширения макроса, которые не привели бы к бесконечной рекурсии (см. Документацию Boost Preprocessor Library для подробное обсуждение этого вопроса ), но стандарт не изменится сейчас.
Если к аргументу макроса применяется ##
, то он подавляет расширение макроса этого аргумента. (См. G CC Руководство, раздел 3.5, Объединение или C Стандарт, §6.10.3.3, параграф 2.) Подавление расширения является частью C стандарта, но GCC / Clang расширение, позволяющее использовать ##
для условного подавления запятой, предшествующей __VA_ARGS__
, является нестандартным. (См. G CC Руководство, раздел 3.6, Variadi c Макросы .) Очевидно, расширение все еще соблюдает правило стандарта о том, что не нужно расширять конкатенированные макро-аргументы.
Теперь, во втором пункте, касающемся необязательного подавления запятых, любопытно то, что вы практически не замечаете этого на практике. Вы можете использовать ##
для условного подавления запятых, и аргументы по-прежнему будут расширяться как обычно:
#define SHOW_ARGS(arg1, ...) Arguments are (arg1, ##__VA_ARGS__)
#define DOUBLE(a) (2 * a)
SHOW_ARGS(DOUBLE(2))
SHOW_ARGS(DOUBLE(2), DOUBLE(3))
Это расширяется до:
Arguments are ((2 * 2))
Arguments are ((2 * 2), (2 * 3))
Оба DOUBLE(2)
и DOUBLE(3)
являются обычно расширяется, несмотря на то, что один из них является аргументом оператора конкатенации.
Но есть и тонкость в расширении макроса. Расширение происходит дважды:
Сначала раскрываются аргументы макроса. (Это расширение находится в контексте текста, который вызывает макрос.) Эти расширенные аргументы заменяются параметрами в теле замены макроса (но только в том случае, если параметр не является аргументом #
или ##
).
Затем операторы #
и ##
применяются к списку токенов замены.
Наконец, полученные токены замены вставляются в входной поток, чтобы они снова расширились. На этот раз расширение происходит в контексте макроса, поэтому рекурсивный вызов подавляется.
Имея это в виду, мы видим, что в SHOW_ARGS(DOUBLE(2), DOUBLE(3))
, DOUBLE(2)
раскрывается на шаге 1, перед вставкой в список токенов замены, и DOUBLE(3)
расширяется на шаге 3 как часть списка токенов замены.
Это не имеет значения с DOUBLE
внутри SHOW_ARGS
, поскольку они разные макросы. Но разница станет очевидной, если они будут одним и тем же макросом.
Чтобы увидеть разницу, рассмотрим следующий макрос:
#define INVOKE(A, ...) A(__VA_ARGS__)
Этот макрос создает вызов макроса (или вызов функции, но здесь нас интересует только тот случай, когда это макрос). То есть по очереди INVOKE(X, Y)
в X(Y)
. (Это упрощение полезной функции, когда названный макрос на самом деле вызывается несколько раз, возможно, с несколько иными аргументами.)
Это прекрасно работает с SHOW_ARGS
:
INVOKE(SHOW_ARGS, one arg)
⇒ Arguments are (one arg)
Но если мы попытаемся INVOKE
сам макрос INVOKE
, мы обнаружим, что запрет на рекурсивный вызов вступает в силу:
INVOKE(INVOKE, SHOW_ARGS, one arg)
⇒ INVOKE(SHOW_ARGS, one arg)
«Конечно», мы можем расширить INVOKE
в качестве аргумента для INVOKE
:
INVOKE(SHOW_ARGS, INVOKE(SHOW_ARGS, one arg))
⇒ Arguments are (Arguments are (one arg))
Это прекрасно работает, потому что внутри INVOKE
нет ##
, поэтому расширение аргумента не подавляется. Но если расширение аргумента было подавлено, то аргумент будет вставлен в тело макроса без расширения, и тогда он станет рекурсивным расширением.
Так вот, что происходит в вашем примере:
#define M0(x, ...) { x, ## __VA_ARGS__ }
M0(M0(1,2), M0(3,4), M0(5,6))
⇒ { { 1,2 }, M0(3,4), M0(5,6) }
Здесь первый аргумент для внешнего M0
, M0(1,2)
не используется с ##
, поэтому он раскрывается как часть вызова. Два других аргумента являются частью __VA_ARGS__
, который используется с ##
. Следовательно, они не раскрываются перед заменой в список замены макроса. Но как часть списка замены макроса, его расширение подавляется правилом no-recursive-macro,
Вы можете легко обойти это, определив две версии макроса M0
с одинаковым содержимым, но разные имена (как предложено в комментарии к OP):
#define M0(x, ...) { x, ## __VA_ARGS__ }
M0(M1(1,2), M1(3,4), M1(5,6))
⇒ { { 1,2 }, { 3,4 }, { 5,6 } }
Но это не очень приятно.
Решение: Используйте __VA_OPT__
C ++ 2a будет включать новую функцию, специально разработанную для подавления запятых в вызовах variadi c: функциональный макрос __VA_OPT__
. Внутри расширения макроса variadi c, __VA_OPT__(x)
расширяется до своего аргумента, при условии, что в аргументах variadi c есть хотя бы один токен. Но если __VA_ARGS__
расширяется до пустого списка токенов, то и __VA_OPT__(x)
. Таким образом, __VA_OPT__(,)
может использоваться для условного подавления запятой точно так же, как расширение G CC ##
, но в отличие от ##
, оно не вызывает подавления расширения макроса.
В качестве расширения стандарта C последние версии G CC и Clang реализуют __VA_OPT__
для C, а также C ++. (См. G CC Руководство, раздел 3.6, Variadi c Макросы .) Так что, если вы хотите положиться на относительно недавние версии компилятора, есть очень чистое решение:
#define M0(x, ...) { x __VA_OPT__(,) __VA_ARGS__ }
M0(M0(1,2), M0(3,4), M0(5,6))
⇒ { { 1 , 2 } , { 3 , 4 }, { 5 , 6 } }
Примечания:
Вы можете увидеть эти примеры на Godbolt
Этот вопрос был изначально задан закрыто как копия макроса Variadi c: расширение вставленных токенов , но я не думаю, что этот ответ действительно адекватен этой конкретной ситуации.