Макрос Variadic, который выводит свои аргументы через `||` - PullRequest
0 голосов
/ 31 декабря 2018

Я хотел бы сделать макрос F, принимающий переменное число параметров, который расширяется до параметров, каждый из которых отделяется ||.например, F(a, b, c) должно расширяться до a || b || c, F(a) должно расширяться до a и т. д.

Я знаю, что C не поддерживает рекурсивные макросы.Мне нужно это только для не более 4 аргументов в настоящее время.

Я думал о чем-то вроде #define F(a, ...) a || F(__VA_ARGS__), а затем о втором макросе, чтобы увеличить его в 4 раза, но я совсем не уверен, как должен выглядеть этот другой макрос.И я сталкиваюсь с проблемой наличия пустого __VA_ARGS__ в какой-то момент.Любые другие идеи будут высоко оценены.

Ограничения: должен работать с любым стандартным компилятором C99.

РЕДАКТИРОВАТЬ: у меня это работает, используя Перегрузка макроса на количество аргументов , но все же любопытно, еслиесть другое решение.

Ответы [ 2 ]

0 голосов
/ 31 декабря 2018

Это довольно тяжелый режим, но если вы можете использовать библиотеки, то Boost.PP может сделать большую часть тяжелой работы за вас.Он поддерживает как C, так и C ++, и является библиотекой только для заголовков (очевидно).Ваш вариант использования будет выглядеть следующим образом:

#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/seq/fold_left.hpp>

#define OP(s, state, x) state || x
#define F(...) BOOST_PP_SEQ_FOLD_LEFT(OP, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))

Вышеприведенный пример преобразует переменные аргументы в расширенную последовательность PP, а затем сворачивает ее, применяя OP.state является промежуточным результатом каждой «итерации».Его начальное «значение» равно 0 (чтобы результирующее выражение не зависело от него).

И при выполнении от F(1, 2, 3) до gcc -E мы получаем:

0 || 1 || 2 || 3

Главное предостережение с пустым списком аргументов (формально расширение GCC, недопустимое C99) заключается в том, что оно будет расширено до 0 ||.Так что это стоит иметь в виду.Подсчет аргументов (с Boost.PP) может быть использован для выбора между одной из двух реализаций в зависимости от 0 или более аргументов для решения проблемы.

0 голосов
/ 31 декабря 2018

Основы довольно просты:

#define COUNT(...) COUNT_(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
#define COUNT_(A0, A1, A2, A3, A4, A5, A6, A7, ...) A7

#define F0()
#define F1(A0) A0
#define F2(A0, A1) A0 || A1
#define F3(A0, A1, A2) F2(A0, A1) || A2
#define F4(A0, A1, A2, A3) F3(A0, A1, A2) || A3

#define F(...) C(F, COUNT(__VA_ARGS__))(__VA_ARGS__)
#define C(X, Y) C_(X, Y)
#define C_(X, Y) X ## Y

, где C - это обычный двухэтапный макрос конкатенации.Однако осталась одна проблема: пустой __VA_ARGS__.

На самом деле, это не поддерживается самим стандартом C (вам придется переключиться на грядущий C ++ 20 для - или, возможно, C20 backports?).И задача довольно тяжелая (как, например, COUNT() уступает 1, где первый аргумент в макросе COUNT_ является пустым!).Мне удалось решить эту проблему для аналогичной задачи довольно давно, так что вы можете взглянуть на там , должно быть достаточно просто импортировать соответствующую часть сюда ...

...