Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ function slash operator lambda expression

in fact I don't know how to be very precise.

Today, I browsed the following page:

http://siliconframework.org/docs/hello_world.html

I found the following syntax:

GET / _hello = [] () { return D(_message = "Hello world."); }

I found "GET" can be a function by lambda expression, but I cannot figure out what does "/" and "_hello" mean here, and how they connect to something meaningful.

Also, what is that "_message = "?

BTW, my primary C++ knowledge is before C++11.

I googled quite a bit.

Could any one kindly give an explanation?

like image 912
mas Avatar asked May 25 '16 08:05

mas


2 Answers

This library uses what is known as an embedded Domain Specific Language, where it warps C++ and preprocessor syntax in ways that allow a seemingly different language to be just another part of a C++ program.

In short, magic.

The first bit of magic lies in:

iod_define_symbol(hello)

which is a macro that generates the identifier _hello of type _hello_t.

It also creates a _hello_t type which inherites from a CRTP helper called iod::symbol<_hello_t>.

_hello_t overrides various operators (including operator= and operator/) in ways that they don't do what you'd normally expect C++ objects to behave.

GET / _hello = [] () { return D(_message = "Hello world."); }

so this calls

operator=(
  operator/( GET, _hello ),
  /* lambda_goes_here */
);

similarly in the lambda:

D(_message = "Hello world.");

is

D( operator=(_message, "Hello world.") );

operator/ and operator= can do nearly anything.

In the D case, = doesn't do any assigning -- instead, it builds a structure that basically says "the field called "message" is assigned the value "Hello world.".

_message knows it is called "message" because it was generated by a macro iod_define_symbol(message) where they took the string message and stored it with the type _message_t, and created the variable _message which is an instance of that type.

D takes an number of such key/value pairs and bundles them together.

The lambda returns this bundle.

So [] () { return D(_message = "Hello world."); } is a lambda that returns a bundle of key-value pair attachments, written in a strange way.

We then invoke operator= with GET/_hello on the left hand side.

GET is another global object with operator/ overloaded on it. I haven't tracked it down. Suppose it is of type iod::get_t (I made up that name: again, I haven't looked up what type it is, and it doesn't really matter)

Then iod::get_t::operator/(iod::symbol<T> const&) is overloaded to generate yet another helper type. This type gets the T's name (in this case "hello"), and waits for it to be assigned to by a lambda.

When assigned to, it doesn't do what you expect. Instead, it goes off and builds an association between "hello" and invoking that lambda, where that lambda is expected to return a set of key-value pairs generated by D.

We then pass one or more such associations to http_api, which gathers up those bundles and builds the data required to run a web server with those queries and those responses, possibly including flags saying "I am going to be an http server".

sl::mhd_json_serve then takes that data, and a port number, and actually runs a web server.

All of this is a bunch of layers of abstraction to make some reflection easier. The structures generated both have C++ identifiers, and similar strings. The similar strings are exposed in them, and when the json serialization (or deserialization) code is generated, those strings are used to read/write the json values.

The macros merely exist to make writing the boilerplate easier.

Techniques that might be helpful to read on further include "expression templates", "reflection", "CRTP", embedded "Domain Specific Language"s if you want to learn about what is going on here.

Some of the above contains minor "lies told to children" -- in particular, the operator syntax doesn't work quite like I implied. (a/b is not equivalent to operator/(a,b), in that the second won't call member operator /. Understanding that they are just functions is what I intend, not that the syntax is the same.)

@mattheiuG (the author of this framework) has shared these slides in a comment below this post that further explains D and the _message tokens and the framework.

like image 123
Yakk - Adam Nevraumont Avatar answered Oct 01 '22 21:10

Yakk - Adam Nevraumont


It's not standard C++ syntax, it's framework specific instead. The elements prefixed with an underscore (_hello, _message etc) are used with a symbol definition generator that runs and creates the necessary definitions prior to compilation.

There's some more information on it on the end of this page: http://siliconframework.org/docs/symbols.html. Qt does a similar thing with its moc tool.

like image 24
Nicholas Smith Avatar answered Oct 01 '22 21:10

Nicholas Smith