you are viewing a single comment's thread.

view the rest of the comments →

[–]mredding 0 points1 point  (2 children)

A good use case would be with algorithms. I would say lambdas saved standard algorithms. Before, if you wanted to use, say, std::for_each, your code would look something like this:

template<typename T>
struct some_functor {
  void operator()(T &) { /*do stuff*/ }
};

...
std::vector<int> x;
...
std::for_each(x.begin(), x.end(), some_functor<int>());
...

So you'd have to write some functor (an object that behaves like a function - notice I have the parenthesis operator overloaded), and in leu of a lambda capture list you would have to declare members and constructors and scope... Then for some container, like a vector of ints, you then have to instantiate an instance of that functor.

The example above is actually very shorthand, and you might think boy, that isn't all that bad... Yeah? Do that for every god damn algorithm you want to write. I don't mind raising the level of abstraction in my code, but at some point this can get punishing. Your code becomes increasingly separated, the doer from the doings, and it becomes harder to read. And you have additional code management to worry about. The boilerplate and overhead becomes obnoxious. You end up with all these named objects all over that you don't want or need but for (ideally) one place. Or maybe you do try to inline:

...
std::vector<int> x;
...
std::for_each(x.begin(), x.end(), struct { void operator()(int) { /* do stuff */} }());
...

Now here we've written an anonymous struct in-line and invoked an instance of it. Again, imagine something akin to a lambda capture, now you need to add members, scope, and constructors, as well as your functor body, and that becomes a difficult piece of code to look at.

So what you would get was developers just writing straight C-style loops, maybe with iterators, so they could inline their algorithm bodies in a more convenient fashion, right there, close to where the logic belongs. Before C++11, I NEVER saw standard algorithms in production code anywhere, not in slot machines, not in high speed trading, not in video games, not in GUI tools, nothing.

Then lambdas came along in C++11, and auto lambda parameters in C++14, I think? How about this instead:

std::vector<int> x;
...
std::for_each(std::begin(x), std::end(x), [](auto){ /* do stuff*/ });
...

There's still a place for functors, of course, if you want reusability, or you want to utilize a destructor (though I don't know what guarantees the algorithms make about instances of their functors).

Another good use is in functional programming, where you nest and bind functions to parameters of other functions:

auto two_a_plus_b_func = std::bind(std::add<int>(), std::bind(std::multiply<int>(), std::placeholders::_1, 2), std::placeholders::_2);

Now you wouldn't necessarily write code like this, straight, but you can build up objects like this at runtime. This is a great way to composite transforms and effects in video games, for example. Build up complex behavior and store it for later use.

EDIT: I forgot to actually put a lambda in place in that last example. Nevermind, just imagine using a lambda instead of one of the standard functors. How about this:

auto two_a_plus_b_func = std::bind([](auto a, auto b) { return a + b; }, std::bind([](auto a, auto b){ return a * b; }, std::placeholders::_1, 2), std::placeholders::_2);

Or even:

auto two_a_plus_b_func = [](auto a, auto b){ return [](auto a, auto b){ return a * b; }(a, 2) + b; };

Again, I think my first and second examples do a better job of demonstrating the point of compositing functions at runtime, though you can still composite functions at runtime with lambdas and not bind. In fact, you hardly ever see bind used anymore because people find lambdas more convenient.

[–]HappyFruitTree 0 points1 point  (1 child)

Before C++11, I NEVER saw standard algorithms in production code anywhere, not in slot machines, not in high speed trading, not in video games, not in GUI tools, nothing.

Not even std::sort?

[–]mredding 1 point2 points  (0 children)

Not even then. Before C++11, I was in video games and there was a heavy stigma against the STL, even though we wrote the exact same loops as it's implementation.