Questa libreria utilizza il cosiddetto linguaggio specifico di dominio incorporato, in cui altera la sintassi del C++ e del preprocessore in modi che consentono a un linguaggio apparentemente diverso di essere solo un'altra parte di un programma C++.
In breve, magia.
La prima 'di magia sta nel:
iod_define_symbol(hello)
che è una macro che genera l'identificatore _hello
di tipo _hello_t
.
Viene inoltre creato un tipo _hello_t
che eredita da un helper CRTP denominato iod::symbol<_hello_t>
.
_hello_t
ignora vari operatori (tra cui operator=
e operator/
) in modi che non fanno quello che ci si aspetterebbe normalmente oggetti C++ a comportarsi.
GET/_hello = []() { return D(_message = "Hello world."); }
quindi questo chiama
operator=(
operator/(GET, _hello),
/* lambda_goes_here */
);
simile nel lambda:
D(_message = "Hello world.");
è
D(operator=(_message, "Hello world."));
operator/
e operator=
può fare quasi nulla.
Nel caso D
, =
non fare alcuna assegnazione - invece, si costruisce una struttura che sostanzialmente dice "il campo chiamato "message"
viene assegnato il valore "Hello world."
_message
sa che è chiamato "message"
perché. è stato generato da una macro iod_define_symbol(message)
dove hanno preso la stringa message
e memorizzati con il tipo _message_t
, e creato la variabile _message
che è un'istanza di quel tipo.
D
accetta un numero o f tali coppie chiave/valore e le raggruppa insieme.
Il lambda restituisce questo pacchetto.
Quindi []() { return D(_message = "Hello world."); }
è un lambda che restituisce un fascio di allegati coppia-chiave, scritti in modo strano.
Abbiamo quindi invocato operator=
con GET/_hello
sul lato sinistro.
GET
è un altro oggetto globale con operator/
sovraccarico su di esso. Non l'ho rintracciato. Supponiamo che sia di tipo iod::get_t
(ho inventato quel nome: di nuovo, non ho cercato di che tipo è, e non importa)
Quindi lo iod::get_t::operator/(iod::symbol<T> const&)
è sovraccarico per generare ancora un altro tipo di supporto. Questo tipo ottiene il nome di T
(in questo caso "hello"
) e attende che venga assegnato da un lambda.
Quando assegnato a, non fa quello che ti aspetti. Invece, si attiva e crea un'associazione tra "hello"
e richiama quella lambda, in cui è previsto che lambda restituisca un insieme di coppie chiave-valore generate da D
.
Passiamo quindi a una o più associazioni di questo tipo a http_api
, che raccoglie questi bundle e crea i dati necessari per eseguire un server Web con quelle query e quelle risposte, includendo eventualmente le diciture "Sto diventando un server http ".
sl::mhd_json_serve
quindi prende quei dati e un numero di porta e in realtà esegue un server web.
Tutto questo è un mucchio di strati di astrazione per rendere più semplice la riflessione. Le strutture generate hanno identificatori C++ e stringhe simili. Le stringhe simili sono esposte in esse e quando viene generato il codice serializzazione json (o deserializzazione), tali stringhe vengono utilizzate per leggere/scrivere i valori JSON.
I macro esistono semplicemente per semplificare la scrittura del foglio di riscaldamento.
Le tecniche che potrebbero essere utili per la lettura includono inoltre "modelli di espressione", "riflessione", "CRTP", incorporato "Dominio specifico del dominio" se si vuole sapere cosa sta succedendo qui.
Alcuni di questi contengono "menzogne ai bambini" minori - in particolare, la sintassi dell'operatore non funziona in modo simile a quanto implicito. (a/b
non è equivalente a operator/(a,b)
, in quanto il secondo non chiama l'operatore membro /
. Capire che si tratta di solo le funzioni è ciò che intendo, non che la sintassi sia la stessa.)
@mattheiuG (l'autore di questo quadro) ha condiviso these slides in un commento sotto questo post che spiega ulteriormente D
ei _message
gettoni e il quadro.
Immagino che 'operator /' –
'D' sia spiegato in quella pagina. Il/è solo la libreria che fa apparire il codice più vicino a ciò che assomiglia. – chris
Sembra un'EDSL che utilizza ampiamente l'overloading dell'operatore. – Quentin