LINUX.ORG.RU

Склейка в define

 , ,


2

2

Не получается заставить работать «склейку», чтобы избавиться от последнего элемента:

#define CAT(left, right) CAT_EXP(left, right)
#define CAT_EXP(left, right) left ## right

#define HEAD(seq) HEAD_EXP1 seq)
#define HEAD_EXP1(x) x HEAD_EXP2(
#define HEAD_EXP2(x)

#define TAIL(seq) TAIL_EXP seq
#define TAIL_EXP(x)

#define ITER(seq) func(HEAD(seq))  ITER0(TAIL(seq))
#define ITER0(seq) ITER1 seq
#define ITER1(seq) ,func(seq) ITER2
#define ITER2(seq) ,func(seq) ITER1

#define ITER1_END
#define ITER2_END

ITER((a) (b) (c) (d) (e) (f))

На выходе, разумеется, это:

func(a) ,func(b) ,func(c) ,func(d) ,func(e) ,func(f) ITER2

Никак не получается присобачить ##, чтобы приклеить к концу _END

Пробовал так:

#define ITER(seq) func(HEAD(seq))  ITER0(TAIL(seq)) ## _END
и так:
#define ITER(seq) func(HEAD(seq)) CAT(ITER0(TAIL(seq)), _END)
результат один и тот же - deftest.c:79:32: error: pasting ")" and «_END» does not give a valid preprocessing token

Кто мне может подсказать, как мне аки прилепить к концу _END? Или в более широком вопросе - мне нужно проитерировать элементы так, чтобы в конце не было запятой.

★★

Последнее исправление: cetjs2 (всего исправлений: 1)
#define EVAL0(...) __VA_ARGS__
#define EVAL1(...) EVAL0 (EVAL0 (EVAL0 (__VA_ARGS__)))
#define EVAL2(...) EVAL1 (EVAL1 (EVAL1 (__VA_ARGS__)))
#define EVAL3(...) EVAL2 (EVAL2 (EVAL2 (__VA_ARGS__)))
#define EVAL4(...) EVAL3 (EVAL3 (EVAL3 (__VA_ARGS__)))
#define EVAL(...)  EVAL4 (EVAL4 (EVAL4 (__VA_ARGS__)))

#define MAP_END(...)
#define MAP_OUT

#define MAP_GET_END() 0, MAP_END
#define MAP_NEXT0(test, next, ...) next MAP_OUT
#define MAP_NEXT1(test, next) MAP_NEXT0 (test, next, 0)
#define MAP_NEXT(test, next)  MAP_NEXT1 (MAP_GET_END test, next)

#define MAP0(f, x, peek, ...) f(x); MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x); MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))

MAP(func, a, b, c, d, e, f)

По мотивам https://github.com/swansontec/map-macro, добавил лишь точки с запятой.

mix_mix ★★★★★
()
Ответ на: комментарий от sambist

а в чем смысл, если можно сделать любым другим генератором кода, при этом код получаемый генератором можно будет читать.

anonymous
()
Ответ на: комментарий от mix_mix

Точка с запятой это не то, мне это в enum вставлять. И все равно в конце символ генерится, не подходит.

sambist ★★
() автор топика

Не понял эту магию с пробелами (не думал, что так можно), но может такой вариант подойдёт:


#define ITER( ...) ITER_(COUNT(__VA_ARGS__), __VA_ARGS__)
#define ITER_(n, ...) ITER__(n, __VA_ARGS__)
#define ITER__(n, ...) comb##n(__VA_ARGS__)

/* Neat trick to obtain number number of variadic arguments. */
#define COUNT(...) COUNT_(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define COUNT_(_1, _2, _3, _4, _5, _6, _7, _8, _9, n, ...) n

/* Helper macros to process variable arguments of macros. */
#define comb9(val, ...) func(val), comb8(__VA_ARGS__)
#define comb8(val, ...) func(val), comb7(__VA_ARGS__)
#define comb7(val, ...) func(val), comb6(__VA_ARGS__)
#define comb6(val, ...) func(val), comb5(__VA_ARGS__)
#define comb5(val, ...) func(val), comb4(__VA_ARGS__)
#define comb4(val, ...) func(val), comb3(__VA_ARGS__)
#define comb3(val, ...) func(val), comb2(__VA_ARGS__)
#define comb2(val, ...) func(val), comb1(__VA_ARGS__)
#define comb1(val)      func(val)

ITER(a, b, c, d, e, f)
gcc -E -o - macro.c
...
func(a), func(b), func(c), func(d), func(e), func(f)

P.S. Понял, наверное, __VA_ARGS__ нету, тогда не подойдёт.

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 2)
Ответ на: комментарий от sambist

Так можно выбрать любой разделитель и выбросить последний при помощи тривиальных изменений:

#define DELIMMAP0 , MAP0
#define DELIMMAP1 , MAP1
#define MAP_GET_END() 0, ,MAP_END 
#define MAP_NEXT0(test, d, next, ...) d ## next MAP_OUT
#define MAP_NEXT1(test, d, next) MAP_NEXT0 (test, d, next, 0)
#define MAP_NEXT(test, next)  MAP_NEXT1 (MAP_GET_END test, DELIM, next)
Остальное как в коде выше. DELIMMAP0/DELIMMAP1 можно переопределить по желанию, вывод:

func(a) , func(b) , func(c) , func(d) , func(e) , func(f)

io ★★
()
Ответ на: комментарий от sambist

а как же кэш/контрольная сумма?

anonymous
()
Ответ на: комментарий от io

Спасибо вам большое. Объединил код, чтобы кому-то еще было проще искать:

#define EVAL0(...) __VA_ARGS__
#define EVAL1(...) EVAL0 (EVAL0 (EVAL0 (__VA_ARGS__)))
#define EVAL2(...) EVAL1 (EVAL1 (EVAL1 (__VA_ARGS__)))
#define EVAL3(...) EVAL2 (EVAL2 (EVAL2 (__VA_ARGS__)))
#define EVAL4(...) EVAL3 (EVAL3 (EVAL3 (__VA_ARGS__)))
#define EVAL(...)  EVAL4 (EVAL4 (EVAL4 (__VA_ARGS__)))

#define MAP_END(...)
#define MAP_OUT

#define DELIMMAP0 , MAP0
#define DELIMMAP1 , MAP1
#define MAP_GET_END() 0, ,MAP_END 
#define MAP_NEXT0(test, d, next, ...) d ## next MAP_OUT
#define MAP_NEXT1(test, d, next) MAP_NEXT0 (test, d, next, 0)
#define MAP_NEXT(test, next)  MAP_NEXT1 (MAP_GET_END test, DELIM, next)

#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))

MAP(func, a, b, c, d, e, f)
sambist ★★
() автор топика

а зачем тебе препроцессор? Твой компилятор не умеет inline?

emulek
()
Ответ на: комментарий от sambist

как вариант: см. директива .irp в GAS..

недостаток средств препроцессора С можно аккуратно компенсировать макросами ассемблера. В вашем случае должно получаться даже читабельнее.

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

И как потом результат использовать вместо enum, как предполагается здесь?

anonymous
()
Ответ на: комментарий от sambist

И все равно в конце символ генерится, не подходит.

Вроде бы запятая в конце допускается в C99, а многие компиляторы допускали её и раньше.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Вроде бы запятая в конце допускается в C99, а многие компиляторы допускали её и раньше.

+1, иногда когда что-то генерю - оставляю запятую - это допустимо

I-Love-Microsoft ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.