taby said:
So, basically, lambda expressions are little functions (anonymous functors) that can be placed in any scope? I read that they now support templates!
I'm not qualified to teach any of this, but interestingly the way i've walked to finally use lambdas seems fine to describe what they actually are.
The thing i always missed was ability to write little function inside a big function. C++11 allowed to do this indirectly, by allowing to write structs or classes inside a function:
void BigFunction ()
{
struct Helper
{
static int LittleFunction (int a, int b)
{
return a+b;
}
};
int x = Helper::LittleFunction (1,2);
int y = Helper::LittleFunction (2,3);
int z = Helper::LittleFunction (3,4);
// yay! finally i don't have to copy paste similar code 3 times! :D
// lambdas are introduced with C++11 too, so i should use just that, but i was too lazy to learn the strange syntax for a long time
}
We could now change the Helper object.
Because it only has one function, we could implement said function in its constructor, to get some more elegant syntax.
Recently i've learned that's exactly what lambdas are, just with even more convenient syntax. So probably that's a good way to look at it.
Regarding lambdas, they can be used to get rid of the cost from using functors, which is similar to a virtual function call. That's worth to share i think. Not everybody might know.
I'm too lazy to write a simple example, so posting some code from my fluid simulator:
#if 0 // slow
void BlockParticlesAdjacencyIterator (const int block,
const float interactRadius, const float delta_x, const float cellMaxRad,
std::function<bool (const int pI)> OpenOuterLoop,
std::function<void (const int aBegin, const int aEnd)> IterateInnerLoop,
std::function<void (const int pI)> CloseOuterLoop
)
#else // fast
template <typename L0, typename L1, typename L2>
void BlockParticlesAdjacencyIterator (const int block,
const float interactRadius, const float delta_x,
L0 OpenOuterLoop, L1 IterateInnerLoop, L2 CloseOuterLoop)
#endif
{
// this function does complex stuff to iterate particles in a sparse grid cell and its neighbors
// i need such iteration sheme often, but i want to write the code only once
// goal is to achieve this without performance penalty (otherwise i would prefer to copy paste the code 10 times)
}
This is basically a helper function to do complex iteration and spatial indexing stuff.
It needs 3 callbacks to implement the functionalities as expected.
But i don't want classic C callbacks, because they would spoil my code with many little functions. I want them to be in function helper objects, so lambdas. So all functionality is grouped inside one big function using this iterator.
This can be done using std::function, but the extra cost is pretty high in my case.
Using templates instead, i can use my lambdas as desired, and there is no extra cost, at least not with Clang compiler. (With MSVC it's 10% still)
You see i have commented out the slow approach. The fast one will of course increase the size of my binary much more, i guess.
Here some example of using the iterator:
auto CloseOuterLoop = [&](const int pI) // just one of the 3 'callbacks' in from of a lambda as example
{
//...
};
BlockParticlesAdjacencyIterator (block, interactRadius, delta_x, OpenOuterLoop, IterateInnerLoop, CloseOuterLoop);
I'm still a C programmer at heart, so i can't illustrate or explain this well, but you get my point.
Basically i use those modern features mostly to avoid code duplication and keep things organized. Helps a lot.
I was thinking about using a similar approach to replace the cumbersome method of having a multi threading job system requiring annoying little callbacks for every stuff we want to multi thread.
I saw the dev of the Physics engine i'm using achieved this actually. He writes a little lambda somewhere, and right below he makes it executing from a job system with one line of code. That's really awesome i think. Not sure if he can avoid the cost of functors, but if the task is heavy this cost becomes negligible.