9

I’ve recently started the process of researching lambdas for personal use. I’ve been coding for a few years now, I’ve released multiple products into the wild, and yet, I’ve never found myself needing to use lambdas. I’ve read the other stack exchange answers for various lambda questions, but I haven’t found an explanation that shows a dead-simple example that really drives the idea that lambdas are necessary (for some situations). After doing a bit of research, I’m not convinced that some of the specific uses of lambdas can’t be implemented with standard functions, however, that doesn’t mean much because my scope of the topic is extremely limited.

Can someone provide a rather simple use case for lambdas that demonstrates how they can be more powerful than typical functions (in the correct situations)?

JosephTLyons
  • 2,075
  • 16
  • 39
  • 5
    You can't use functions as a replacement for capturing lambdas, but you *can* use `struct`s with an appropriate `operator()`. It's just that the struct is made of 90% unnecessary boiler plate which you skip using a lambda. – nwp Nov 06 '17 at 11:01
  • I used it once for sorting a vector of some custom data type so I just defined a lambda function. But I just realized I could have also used `std::greater`. So I'm also curious to see answers – Philipp Nov 06 '17 at 11:03
  • What do you mean "more powerful"? IMHO, lambdas are only a tool. If one does not see any reason to use it, do not use it. – megabyte1024 Nov 06 '17 at 11:04
  • @megabyte1024- Well, I specially mentioned “more powerful... (in the correct situations). Similar to how a vector is more powerful than an array in some situations and an array is more powerful than a vector in others. I was specially asking for situations where lambdas have the upper hand, however, based on current answers, my wording may not be applicable. – JosephTLyons Nov 06 '17 at 11:07
  • While about functors, [this question](https://stackoverflow.com/questions/356950/c-functors-and-their-uses) very thoroughly answers your question, and as of C++11 lambdas now fit in most of those use cases – Cory Kramer Nov 06 '17 at 13:06

3 Answers3

18

C++ was Turing complete long before C++11. Lambdas aren't there for making something impossible into a possibility. You can accomplish much without them. They are there to streamline certain pieces of code.

For instance, to allow on-the-fly creation of functors to the standard algorithm library. Sure you can define one on your own. But that requires going outside your funcion, and naming a new type. A whole lot of boilerplate for a simple call to std::transform, as an example.

They keep code localized, don't require you to pollute any namesapces, and are easy to use once you get the hang of it.


As a bonus, in his talk about functional C++, Kevlin Henney reduces an example function from a framework into something that really cries out "use a lambda". So to borrow a little from his talk, consider a command registration function:

void register_command(std::string cmdName, std::function<void()> f);

You want to register a command that just turns on a light bulb. How much boilerplate would you need to write for a custom functor, compared to the following?

register_command("Turn On Light-bulb", [&light_controller]() {
  light_controller.on();
});

Ponder that, and which code base you'd personally rather maintain.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
7

Everything that can be done with lambdas nowadays could have been done in C++03 by handwriting a struct/class with an overloaded operator() (commonly called "functors"). There was a huge issue with that: lack of terseness and lack of locality.

Imagine passing a templated predicate to something like std::find_if in C++03:

struct predicate
{
    template <typename T>
    bool operator()(const T& x) { return boop(x); }
};

void foo()
{
    something(std::find_if(c.begin(), c.end(), predicate()));
}

You need to:

  • Define predicate somewhere, potentially far away from where it's used.

  • Have boilerplate for the struct and the operator() overload.

  • Jump around in the source code while reading it, to understand what predicate is doing.

Compare that to a C++14 generic lambda:

void foo()
{
    something(std::find_if(c.begin(), c.end(), 
        [](const auto& x){ return boop(x); });
}

Boom. Everything is there, local, with minimal boilerplate.


Lambdas are not magic. They purely are syntactic sugar. But I'm my opinion, they're "syntactic sugar to handwritten structs" as "C++ is syntactic sugar to C".

They change the way you write code, they make functional paradigms (e.g. higher-order functions) viable, and can make your code more powerful and safer.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • `struct`s aren't really a thing in C++. Plus you make it sound like one must use the `struct` keyword. – juanchopanza Nov 06 '17 at 11:11
  • 2
    @juanchopanza: `struct` is a thing - it's equivalent to `class` except that it's `public` by default. This is often the best choice for simple "lambda-like" function objects in C++03. I'll improve the answer to clarify that `struct` is not the only thing that can be used. – Vittorio Romeo Nov 06 '17 at 11:16
  • `struct` is a keyword to declare or define a class. A "struct" isn't a thing. – juanchopanza Nov 06 '17 at 12:37
2

We can possible do almost everything without using lambdas. However lambdas are introduced to support functional programming and is useful in many cases.

I've recently used it in threads and it made my life easier. Here is a very simplified version

int main() {
    int value = 0;

    thread th { [=](){ 
        cout<<"I am inside thread fn Value = "<<value<<endl;
    }};

    th.join();
}

There are two obvious benefits over here

  1. The lambda prevented creation of a global or class static function
  2. I don't need to pass parameters to threads ( A complex thing to do), because lambda closure takes care of that.

So there are few cases where lambda may be a better option, but it doesn't mean that we can't do the same with functions

DeepakKg
  • 349
  • 2
  • 4