препроцессор c — Стиль функционального программирования в макросах C ++: документировано ли это где-нибудь?

Читая некоторый код 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)) гораздо проще.)

Мои вопросы:

  • Есть ли настоящее имя для этого поведения?
  • Это где-нибудь задокументировано?
  • Он широко используется или есть известные подводные камни и т. Д.?

1

Решение

Идея придумана «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-макрокоманд не должно вносить большой вклад во время компиляции реальной программы. Просто их простое потенциальное существование проникает в реальное слово и винты с головками компилятора.

4

Другие решения

Вот несколько лекций: С чисто функциональный,

Я предлагаю вам взглянуть на libpp, macrofun,

1

По вопросам рекламы [email protected]