Хотя это плохая идея, это можно сделать, так что это один из способов.
Вы можете на самом деле зациклиться на препроцессоре и определить рекурсивные макросы, если используете подходящую мощную библиотеку метапрограммирования, например Order (как упоминалось выше, Boost - еще один возможный кандидат). Заказ позволяет вам программировать в функциональном стиле, знакомом всем, кто знает Scheme или ML.
Для осуществления цикла используйте конструкцию for_each
. Для того, чтобы просто создать заданное число то, что вы можете использовать for_each_in_range
с 1, N+1
:
ORDER_PP( // within this block Order code runs
8for_each_in_range(8fn(8_, 8print((*))),
1, 8)
)
выше напечатает 7 звезд. Вы можете обернуть метапрограммных блоки внутри обычных макросов, которые следуют обычным правилам препроцессора:
// print COUNT stars
#define STARS(COUNT) ORDER_PP(\
8for_each_in_range(8fn(8_, 8print((*))), 1, 8plus(COUNT, 1)) \
)
в пределах ORDER_PP
блока, все предполагается код заказа, а не C код препроцессор, который означает только признанные функции Order можно назвать (и все значения/токены предварительной обработки должны быть либо сырыми ints, либо «кавычками» с конструкцией 8(val)
). Для определения stars
как функции Order вместо макроса CPP, так что она может быть вызвана из ORDER_PP
как часть вложенного выражения, мы должны написать это:
#define ORDER_PP_DEF_8stars ORDER_PP_FN(\
8fn(8C, 8for_each_in_range(8fn(8_, 8print((*))), 1, 8plus(8C, 1))))
ORDER_PP(8stars(7)) // prints 7 stars
Order предоставляет рекурсию полностью прозрачно, поэтому написание вложенных циклов инициализатора относительно проста:
#define ORDER_PP_DEF_8ndim_init ORDER_PP_FN(\
8fn(8N, 8T, 8C, 8I, 8D, \
8do(\
8print(8N (=malloc) 8lparen 8seq_head(8D) (*sizeof) 8lparen 8T 8stars(8minus(8C, 1)) 8rparen 8rparen (;)), \
8if(8equal(8C, 1), \
8print(((void)0;)), \
8do(\
8print((for) 8lparen (int) 8I (=0;) 8I (<) 8seq_head(8D) (;) 8I (++) 8rparen ({)), \
8ndim_init(8adjoin(8N, 8([), 8I, 8(])), 8T, 8minus(8C, 1), 8cat(8I, 8(_K)), 8seq_tail(8D)), \
8print((})) \
)))))
Invoke ndim_init
так:
// print the nested initializer from the question
ORDER_PP(
8ndim_init(8(nda), 8(int), 3, 8(i), 8seq(8(n1), 8(n2), 8(n3)))
)
Обратите внимание, что имена переменных C (, i
и т. Д.) Необходимо указывать при появлении в блоке ORDER_PP
, чтобы Заказ обрабатывал их как текст, вместо того, чтобы их оценивать. Последний аргумент - это список переменных времени выполнения, которые будут содержать размеры для каждого измерения (8seq
строит список, 8
снова цитирует имена переменных C).
Вы можете запрограммировать вызов ndim_init
в обычный макрос препроцессора для удобства доступа, как и первый пример с STARS
; Вы можете комбинировать его с описателем макро легко таким образом, чтобы излучать объявление и инициализацию в одном вызове:
#define NDIM(NAME, TYPE, ...) ORDER_PP (\
8lets((8D, 8((__VA_ARGS__))) \
(8C, 8tuple_size(8D)), \
8do(\
8print((TYPE) 8stars(8C) (NAME; {)), \
8ndim_init(8(NAME), 8(TYPE), 8C, 8(_ITER), 8tuple_to_seq(8D)), \
8print((})) \
)) \
)
NDIM(nda, int, n1, n2, n3) // emits declaration and init block for int ***nda
More Order examples
Если выше, похоже, не просто вообще .. поэтому люди говорят, что вы не должны этого делать. (Если это так, хорошо для вас, никто не сможет читать ваш код.)
Поскольку код скомпилирован, что такое использование для TypeName во время выполнения? – Jiminion
Что-то подсказывает, что проблема здесь не в объявлении указателя на n-уровни косвенности. Скорее всего, это будет * почему * вы хотите сделать это в первую очередь. – WhozCraig
Извините за путаницу, я изменил вопрос. – user2690457