9

I am confused with some of the examples that I have come across with C++11 lambdas. For eg:

#include <iostream>
#include <string>

using namespace std;

int main()
{ 
        cout << []()->string{return "Hello World 1!";}() << endl;

        []{cout << "Hello World 2!" << endl;}();

        string result = [](const string& str)->string {return "Hello World " + str;}("2!");
        cout << "Result: " << result << endl;

        result = [](const string& str){return "Hello World " + str;}("3!");
        cout << "Result: " << result << endl;

        string s;
        [&s](){s = "Hello World 4!";};   // does not work
        cout << s << endl; 
        [&s](){s = "Hello World 4!";}(); // works!
        cout << s << endl;

        return 0;
}

I am unable to figure out what the parentheses at the end are doing. Are they instantiating, as a constructor, a lambda? Given that the template for a lambda is:

[capture_block](parameters) mutable exception_specification -> return_type {body}

it baffles me that those parentheses are required for those instances to work. Can someone explain what they are why they are required?

Xeo
  • 129,499
  • 52
  • 291
  • 397
Quiescent
  • 1,088
  • 7
  • 18
  • 1
    This is a shining example on why lambdas are something that should be used sparingly. I had to read that code about 5 times over to understand the full intent. – Richard J. Ross III Sep 30 '12 at 16:16
  • 3
    @Richard: Sorry, no, it's not. This is the prime example of how to *misuse* them. You don't normally call it in the exact same expression that you create it in. – Xeo Sep 30 '12 at 16:26
  • @PeteBecker The point of "hello world" programs is to be dense, so the reader doesn't think about the purpose behind it. – leemes Sep 30 '12 at 16:43
  • 1
    @leemes - the usual C and C++ hello world programs are nowhere near as dense as this code. – Pete Becker Sep 30 '12 at 16:52
  • 2
    @Xeo One useful example where you define and immediately use a lambda is to assign a const variable a value which needs some complex initialization code: `const int x = []{ some init code }();` So you don't need a separate function just to make `x` const for the rest of its life. However, I can be wrong (again) :) – leemes Sep 30 '12 at 18:04
  • 1
    @leemes: I specifically said you *normally* don't call it immediately. ;) The same holds for initializing static members with a one-off function. – Xeo Sep 30 '12 at 18:16

2 Answers2

15

Well, given that a lambda expression is basically an anonymous function, the parentheses at the end do nothing more than just call this function. So

result = [](const string& str){return "Hello World " + str;}("3!");

is just equivalent to

auto lambda = [](const string& str){return "Hello World " + str;};
string result = lambda("3!");

This holds in the same way for a lambda with no arguments, like in

cout << []()->string{return "Hello World 1!";}() << endl;

which would otherwise (if not called) try to output a lambda expression, which in itself doesn't work. By calling it it just puts out the resulting std::string.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
8

They're calling the function object!

In two phases:

auto l = []()->string{return "Hello World 1!";}; // make a named object
l(); // call it

A lambda expression evaluates to a function object. Since there's no operator<< overload that takes such a function object, you'd get an error if you didn't call it to produce a std::string.

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • 1
    Is this really called a function *object*? I thought one should distinguish between function objects (= objects which implement `operator()` to behave similar to a function) and ***lambda** functions*. Different concepts, different usage, similar use cases. – leemes Sep 30 '12 at 16:18
  • 3
    @leemes: Except, lambdas *are* function objects. They implement `operator()`. – Xeo Sep 30 '12 at 16:19
  • Thanks to point that out! :) So they are just some syntax sugar to *define and create* function objects (derived from `std::function(...)` in one step? I just want to understand the details of *what exactly they are*. – leemes Sep 30 '12 at 16:20
  • 3
    @leemes: First, they're not derived from `std::function`, second [check this link](http://stackoverflow.com/q/7627098/500104). The lambda expression creates an unnamed unique type and object of that type in the scope of the expression, which contains the `operator()` aswell as the captures in some way. At the point the lambda expression was written, this object is used instead. – Xeo Sep 30 '12 at 16:27
  • Thank you very much for this clarification. I accidentally thought they would derive from `std::function` because of some code snipped I saw where one used this to allow the storage of the lambda as a class member, see [here](http://stackoverflow.com/questions/6601930/c11-lambda-as-member-variable). I just wanted to know which type a lambda function is of. Now I got it I think ;) – leemes Sep 30 '12 at 16:40
  • 1
    @leemes: `std::function` (and its boost equivalent) allow *storage* of any given callable entity. A lambda-derived function object is such a callable entity, so it can be stored. :) – Xeo Sep 30 '12 at 16:45
  • 1
    @leemes `std::function` is a container that stores function objects (or any callables), they don't derive from it, actually nobody should ever derive from `std::function` (at least not for simple everyday reasons). – Christian Rau Sep 30 '12 at 18:17