Почему вариадические макросы так неприятны? - PullRequest
0 голосов
/ 05 марта 2019

Variadic макросы в CPP (препроцессор C / C ++; для простоты я буду рассматривать его как отдельный, отдельный язык в этом вопросе) крайне ограничены по сравнению, например, с вариационными шаблонами C ++. По сути, переменные макросы - это просто макросы с параметром, аргумент которого может содержать запятые. Это не обеспечивает простой способ подсчета аргументов, оперирования аргументами один за другим и т. Д. Эти вещи возможны , но требуют сложных, запутанных и медленных для компиляции хаков, таких как описанные в этот вопрос . Единственное, что примерно прямо связано с VA_ARGS, - это передать их в функцию с переменным числом.

Мой вопрос: почему они были разработаны таким образом? Стандартный подход к спискам на любом чисто функциональном языке, таком как CPP, заключается в сопоставлении шаблонов в стиле «против»: обрабатывает первый аргумент списка и рекурсивно для остальных, а также имеет базовый случай для пустого списка. Члены комитета по стандартам были бы хорошо знакомы с этим подходом.

Почему такой подход не использовался для вариационных макросов CPP? Считалось ли, что макросы с переменными числами рассматриваются просто как способ обёртывания функций с переменными числами, чтобы не требовалось оперировать списком аргументов? Была ли какая-то основная проблема, из-за которой было бы нецелесообразно разрешать вариационные макросы повторяться? Или ...?

ПРИМЕЧАНИЕ: я не ищу ответы / комментарии в форме «потому что люди не должны хотеть вариационные макросы». Существование таких вещей, как boost.preprocessor, указывает на то, что разумные люди хотели использовать препроцессор нетривиальными способами. Также не ищите личного мнения о том, почему какой-то другой дизайн был бы хорошей / плохой идеей. Я пытаюсь выяснить фактические рассуждения того времени.

Ответы [ 3 ]

4 голосов
/ 05 марта 2019

Вариативные макросы, унаследованные от C ++ от C.

Clive Feather написал статью о добавлении вариационных макросов в C.

Бумага, N580: Varargsдля функционально-подобных макросов состояния:

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

[...]

Можно было бы предоставить дополнительные средства, но это было оставлено для дальнейших предложений.

Один вопрос заключается в том, следует лиможно разрешить нулевым фактическим аргументам соответствовать конечному параметру.Было решено не допустить этого, поскольку это лучше согласуется с другим предложением, сделанным отдельно.

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

В C ++ макросы являются гражданами второго сорта.C ++ редко вводит новшества с новым синтаксисом или функциями макросов, а вместо этого разрабатывает способы решения проблемы без макроса.

C больше не вводит новшеств.

Реальные макросы vararg, добавленные в C, приходятиз бумаг, полученных из этого, но у этого был самый ясный мотивационный текст позади этого решения.

3 голосов
/ 05 марта 2019

Конечно, кажется, что целью было просто быть оберткой для функций с переменными числами.Variadic макросы были введены в C99, а затем гораздо позже в C ++ 11.Обоснование C99 V5.10 6.10.3 предлагает следующее объяснение:

Новая функция C99: C89 представила стандартный механизм определения функций с переменным числом аргументов, но сделалане разрешать любые способы написания макросов с тем же свойством.Например, нет способа написать макрос, который выглядит как вызов printf.

Эта возможность теперь доступна.Определение макроса аналогичным образом использует многоточие для указания списка переменных аргументов.Однако, поскольку подстановка макросов является текстовой, а не во время выполнения, для указания места замены аргументов используется другой механизм: идентификатор __VA_ARGS__.Это заменяется всеми аргументами, которые соответствуют многоточию, включая запятые между ними.

Хотя есть и несколько других вариантов использования __VA_ARGS__, но это может быть скорее совпадением.Например, вы можете использовать переменные макросы для подсчета количества элементов, присутствующих в списке инициализатора.

1 голос
/ 05 марта 2019

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

В предложении упоминается, что отсутствие нулевых фактических аргументов "лучше согласуется с другим предложением". Первоначально я думал, что это означает, что «Недопущение нулевых аргументов позволяет этому предложению быть совместимым с другим», но на самом деле значение кажется ближе к «Допуск нулевых аргументов должен быть частью другого предложения». Хотя я не могу найти предложение, на которое можно сослаться, я нашел его публичный комментарий , предлагающий ключевое слово __VA_COUNT__. Если предположить, что этот комментарий представляет собой хотя бы часть основной идеи его другого предложения, то __VA_COUNT__ - это то, что нужно для более сложного использования вариационных макросов.

Кажется вероятным, что N580 (и его преемники) представляли популярное и неоспоримое предложение разрешить varargs проходить через макрос, в то время как __VA_COUNT__ был компонентом более богатой предварительной обработки variadics (либо через MACRO_ARGS_1, MACRO_ARGS_2 и т. Д., Или через какой-то другой, неизвестный механизм), и только первое предложение достигло консенсуса.

...