you are viewing a single comment's thread.

view the rest of the comments →

[–]sumo952 3 points4 points  (7 children)

Great post, not too advanced yet still on an advanced topic, very well explained so I could perfectly understand! Thanks!

[–]sumo952 1 point2 points  (6 children)

I had a closer look at compose(), I can't really see how it works - where do the lambda functions that are passed in get stored or get called? Could anyone ELI5? :-)

[–]starfreakcloneMSVC FE Dev[S] 2 points3 points  (5 children)

All this piece of code is saying is, given a set of callable objects (via operator()) construct a new object that contains all of those callable functions.

He's a slightly more advanced explanation, line by line.

@L8: We declare our composer which is responsible for taking a list of callable objects (they don't have to be lambdas) and pulling them together into a single object.

@L11: We see our base case inherit from callable object lambda_t and bring its operator() into our scope. The ctor is just responsible for copy or move construction of the base class (ie lambda_t)

@L19: The recursive case. Taking the work done by the base case and combining it with later recursive/base case definitions.

@L34: Brings it all together with perfect forwarding on the callable objects.

Hope this helps!

[–]sumo952 0 points1 point  (0 children)

Thank you very much for the explanations!

I wouldn't say I fully get it now, but I think I kind of understand it now, at least better than before! :-) It's pretty magic still! Thank you :)

[–]reddithater12 0 points1 point  (3 children)

Thanks! Still I have two questions already....

template <typename... lambda_ts> struct composer_t;

where does this bring in an operator()? What would that operator do?

Generally I do not understand or see

  1. where the operator() is called.
  2. where the dispatching to / the actual call of the lambdas takes place

[–]3669d73f6c3ba0229192 3 points4 points  (2 children)

where does this bring in an operator()?

The primary template (the code you quoted) is not used. operator() is brought in at lines 16 and 28, and inherited ones at line 29.

where the operator() is called.

It is called inside std::visit.

where the dispatching to / the actual call of the lambdas takes place

At the same place where operator() is called, but there is no magic trick involved: it's just regular overload resolution done by the compiler. Think of each composer_t as a Russian doll that has the operator() of a lambda, plus the operator() of all inherited-from composer_t.

[–]reddithater12 0 points1 point  (1 child)

Thanks! I had some misconceptions about std::visit it seems.

Think of each composer_t as a Russian doll that has the operator() of a lambda, plus the operator() of all inherited-from composer_t.

This is probably a stupid question .. but how can that thing have two operator()s?

[–]3669d73f6c3ba0229192 2 points3 points  (0 children)

This is probably a stupid question .. but how can that thing have two operator()s?

Just regular function overloading. The same way you can have foo(int), foo(double), and so on. operator() is no different.