Я пытаюсь написать макрос, который подсчитывает количество конкретных элементов в последовательности. Например. для последовательности (A) (B) (A) Я хочу, чтобы получить количество 2 для А.
Теперь принимая подход от https://stackoverflow.com/a/12540675/2525536 я в конечном итоге с этим кодом:C препроцессор - рекурсивный условный счетный макрос
#define CAT(x, ...) CAT1(x, __VA_ARGS__)
#define CAT1(x, ...) CAT2(x, __VA_ARGS__)
#define CAT2(x, ...) x ## __VA_ARGS__
#define EXPAND(...) __VA_ARGS__
#define EAT(...)
#define DEFER(...) __VA_ARGS__ EAT()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EAT)()
#define SIZE(seq) CAT(SIZE_, SIZE_0 seq)
#define SIZE_0(...) SIZE_1
#define SIZE_1(...) SIZE_2
#define SIZE_2(...) SIZE_3
#define SIZE_3(...) SIZE_4
#define SIZE_SIZE_0 0
#define SIZE_SIZE_1 1
#define SIZE_SIZE_2 2
#define SIZE_SIZE_3 3
#define SIZE_SIZE_4 4
#define GET_FIRST(x) GET_FIRST2(GET_FIRST1 x)
#define GET_FIRST1(x) x, EAT()
#define GET_FIRST2(x) GET_FIRST3(x)
#define GET_FIRST3(x, ...) x
#define POP_FIRST(x) EAT x
#define EVAL(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL3(EVAL3(__VA_ARGS__))
#define EVAL3(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) __VA_ARGS__
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define CHECK_PROBE(x) x, 1,
#define NOT(x) CHECK(CAT(NOT_, x))
#define NOT_0 ~, 1,
#define COMPL(b) CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define BOOL(x) COMPL(NOT(x))
#define IIF(c) CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define IF(c) IIF(BOOL(c))
#define WHEN(c) IF(c)(EXPAND, EAT)
#define INC(x) CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define DEC(x) CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define COUNT_IF(tpl, data, x) COUNT_IF1(0, SIZE(x), 0, tpl, data, x)
#define COUNT_IF1(i, n, count, tpl, data, x) \
IF(n) (\
OBSTRUCT(CAT) (\
COUNT_IF3_, \
tpl(i, data, GET_FIRST(x)) \
) (\
OBSTRUCT(COUNT_IF2)() \
(INC(i), DEC(n), count, tpl, data, POP_FIRST(x)) /* call recursive */ \
) \
, count \
)
#define COUNT_IF2() COUNT_IF1
#define COUNT_IF3_0 EXPAND
#define COUNT_IF3_1 INC
#define A_EQUAL_A(...) 1
#define A_EQUAL_B(...) 0
#define COUNT_A(i, data, x) CAT(A_EQUAL_, x)(i)
EVAL(COUNT_IF(COUNT_A, ~, (A)))
EVAL(COUNT_IF(COUNT_A, ~, (B)))
EVAL(COUNT_IF(COUNT_A, ~, (A)(B)))
EVAL(COUNT_IF(COUNT_A, ~, (B)(A)))
EVAL(COUNT_IF(COUNT_A, ~, (A)(A)))
EVAL(COUNT_IF(COUNT_A, ~, (B)(B)))
EVAL(COUNT_IF(COUNT_A, ~, (A)(B)(A)))
Это работает уже довольно хорошо первые 4 примера, но заканчиваются неправильным расширением имени макроса для других (где INC или EXPAND необходимо развернуть более одного раза).
Причина, вероятно, в том, что макросы отмечены синим цветом в C, поэтому это работает https://stackoverflow.com/a/11640759/2525536.
Но я не могу найти обходной путь для этого.
Любая идея?
Я не могу не задаться вопросом, является ли препроцессор C правильным инструментом для этой работы, каков бы он ни был. Это похоже на [XY Problem] (http://mywiki.wooledge.org/XyProblem). –
Конечно, это часть другой проблемы. Я хочу применить макрос к последовательности, если последовательность содержит определенный элемент/токен, в конце концов. Самый короткий путь, по моему мнению, состоял в том, чтобы подсчитать случаи этого токена и проверить результат на 0. – user2525536
Я должен согласиться с Джонатаном Леффлером здесь. Обходным решением будет внедрение грамотного генератора кода, поскольку препроцессор C не является. Даже если вам удастся реализовать это, код будет неуправляемым, и SO на самом деле не является местом для вопросов и ответов об искусстве обфускации кода. –