Читая некоторый код C ++, я наткнулся на то, что я назову «функциональным» использованием функции Macros примерно следующим образом (это полностью стилизованный пример, чтобы пояснить это):
#define TOP_LEVEL(ARG1) \
ARG1("foo1","bar1") \
ARG1("foo2","bar2")
#define NEXT_LEVEL(ARG2A, ARG2B) \
cout << ARG2A << " and " << ARG2B;
TOP_LEVEL(NEXT_LEVEL)
Я относительно новичок в языке, и сначала я не мог понять это, но потом я прогнал его только через препроцессор (g++ -E
) и вот оно решает:
cout << "foo1" << " and " << "bar1"; cout << "foo2" << " and " << "bar2";
Ты видишь, что он там делал? Он прошел макрос NEXT_LEVEL как указатель на функцию к макросу TOP_LEVEL. Видя, насколько это может быть полезно, я хотел узнать больше об этом: передача функций другим функциям довольно сложные вещи и должно быть что-то еще, чтобы сказать о технике.
Тем не менее, несмотря на массу поисков в Google, я не могу найти доказательств того, что эта особенность препроцессора даже существует, не говоря уже о чем-то близком к документации: Вот, Вот, Вот а также Вот это всего лишь четыре примера учебников по макросам, которые пропускаются сразу после этого; у последнего даже есть раздел под названием «Продвинутые трюки с макросами» — конечно, это подходит !?
(Обратите внимание, что это полностью отличается от простого вызова макроса функции с другим оценивали функция макроса в качестве аргумента — FOO (BAR (2)) гораздо проще.)
Мои вопросы:
Идея придумана «X-Macro». Некоторые определения не будут включать ваш конкретный пример (X-макросы, как правило, более сложны, с включенным файлом), но любую соответствующую информацию. об этом подпадает под этот термин при поиске.
Как Крис Упомянутый в комментариях Boost.Preprocessor использует эту идею с большим эффектом. Популярное использование: BOOST_PP_REPEAT
, BOOST_PP_LIST_FOR_EACH
и наиболее сильно: BOOST_PP_ITERATE
,
BOOST_PP_ITERATE
«настоящий» X-Macro; включение одного файла расширяется до чего-то зависимого от макроса, определенного ранее. Я показываю более «правильную» структуру скелета в этом другой ответ, но пример будет:
// in xyz_data.def
DEFINE_XYZ(foo, 1, "Description A")
DEFINE_XYZ(bar, 5, "Description B")
DEFINE_XYZ(baz, 7, "Description C")
Потом, когда я просто хочу столбец 1, я могу сделать:
#define DEFINE_XYZ(name, number, desc) some_func(name)
#include "xyz_data.def"
И где-то еще, где я хочу создать какую-то функцию для каждой, я могу сделать:
#define DEFINE_XYZ(name, number, desc) \
int BOOST_PP_CAT(get_number_for_, name)() \
{ \
std::clog << "Getting number, which is: " desc << std::endl; \
\
return number; \
}
#include "xyz_data.def"
Затем вы можете создать перечисление, в котором имя равно числу и т. Д.
Сила в том, что когда я хочу добавить новый xyz, я просто добавляю его в одном месте, и он волшебным образом появляется везде, где должен быть. Я сделал что-то подобное в очень большой кодовой базе, чтобы хранить некоторые данные закладок в одном центральном месте, но различные атрибуты использовались по-разному в разных местах.
Обратите внимание, что часто это невозможно обойти; что у меня есть синтаксически разные, поэтому никакая другая языковая функция не будет обобщать его для меня до этого уровня, только макросы. Макросы не являются злом.
То, что у вас есть, — это, по сути, X-макрос, в котором файл .def достаточно самодостаточен, чтобы быть #define
, Другими словами, #include "xyz_data.def"
просто TOP_LEVEL
,
У этого есть только один большой недостаток, и по иронии судьбы это не использование самих X-макросов, а их влияние на компиляторы C и C ++. Проблема в том, что препроцессор позволяет нам изменять предварительно обработанный результат файла каждый раз, когда он включается, даже если содержимое файла точно так же.
Возможно, вы слышали, что C и C ++ компилируются медленно по сравнению с современными языками, это одна из причин, почему. У него нет подходящей системы модуля / упаковки, только специальное включение других файлов. И мы только что узнали, в общем, этого нельзя избежать. К сожалению. (Тем не менее, компиляторы умны и заметят, когда вы, например, включаете средства защиты вокруг файла и избегаете его многократной обработки. Но это ситуативно.)
Тем не менее, использование самих X-макрокоманд не должно вносить большой вклад во время компиляции реальной программы. Просто их простое потенциальное существование проникает в реальное слово и винты с головками компилятора.
Вот несколько лекций: С чисто функциональный,