Ответ 1
В этой библиотеке используется так называемый встроенный доменный специфический язык, где он искажает синтаксис С++ и препроцессора способами, которые позволяют кажущемуся другому языку быть просто еще одной частью программы на С++.
Короче говоря, магия.
Первый бит магии заключается в следующем:
iod_define_symbol(hello)
который является макросом, который генерирует идентификатор _hello
типа _hello_t
.
Он также создает тип _hello_t
, который наследует от CRTP-помощника, который называется iod::symbol<_hello_t>
.
_hello_t
переопределяет различные операторы (включая operator=
и operator/
) способами, которые не делают то, что вы обычно ожидаете от поведения объектов С++.
GET / _hello = [] () { return D(_message = "Hello world."); }
поэтому он вызывает
operator=(
operator/( GET, _hello ),
/* lambda_goes_here */
);
аналогично в лямбда:
D(_message = "Hello world.");
является
D( operator=(_message, "Hello world.") );
operator/
и operator=
могут делать почти что угодно.
В случае D
=
не выполняет никаких присваиваний - вместо этого он строит структуру, которая в основном говорит, что для поля, называемого "message"
, присваивается значение "Hello world."
.
_message
знает, что он называется "message"
, потому что он был сгенерирован макросом iod_define_symbol(message)
, где они взяли строку message
и сохранили ее с типом _message_t
, и создали переменную _message
, которая экземпляр этого типа.
D
принимает несколько таких пар ключ/значение и связывает их вместе.
Лямбда возвращает этот пакет.
Итак, [] () { return D(_message = "Hello world."); }
- это лямбда, которая возвращает пучок вложений в пару ключей, написанных странным образом.
Затем мы вызываем operator=
с GET/_hello
в левой части.
GET
- это еще один глобальный объект с operator/
, перегруженным на нем. Я не отслеживал это. Предположим, что это тип iod::get_t
(я составил это имя: опять же, я не искал, какой тип он есть, и это не имеет большого значения)
Затем iod::get_t::operator/(iod::symbol<T> const&)
перегружается для создания еще одного вспомогательного типа. Этот тип получает имя T
(в данном случае "hello"
) и ожидает, что ему будет присвоен лямбда.
При назначении, он не выполняет то, что вы ожидаете. Вместо этого он отключается и создает связь между "hello"
и вызовом этой лямбда, где ожидается, что лямбда вернет набор пар ключ-значение, сгенерированных с помощью D
.
Затем мы передаем одну или несколько таких ассоциаций в http_api
, которая собирает эти пакеты и строит данные, необходимые для запуска веб-сервера с этими запросами и этими ответами, возможно, включая флаги: "Я собираюсь быть http сервер".
sl::mhd_json_serve
затем берет эти данные, номер порта и фактически запускает веб-сервер.
Все это - куча слоев абстракции, чтобы сделать некоторое отражение легче. Созданные структуры имеют И ++ идентификаторы и аналогичные строки. Аналогичные строки отображаются в них, и когда генерируется код сериализации json (или десериализации), эти строки используются для чтения/записи значений json.
Макросы просто существуют, чтобы облегчить запись шаблона.
Методы, которые могут быть полезны для дальнейшего чтения, включают в себя "шаблоны выражений", "отражение", "CRTP", встроенный "Язык конкретных доменов", если вы хотите узнать о том, что здесь происходит.
Некоторые из вышеперечисленных содержат незначительную "ложь, рассказанную детям" - в частности, синтаксис оператора не работает так, как я подразумевал. (a/b
не эквивалентен operator/(a,b)
, поскольку второй не будет вызывать оператор-член /
. Понимая, что это просто функции, я намерен, а не то, что синтаксис один и тот же.)
@mattheiuG (автор этой структуры) поделился этими слайдами в комментарии ниже этого сообщения, которое далее объясняет D
, а _message
токены и рамки.