"Hello Lambdas" C++ 0x, a quick guide to Lambdas in C++

The current draft of the new C++ 0x standard includes lambda functions. I think we can expect this to be very popular. I'll show a "Hello, World" example, and then explain the syntax very briefly. In a future posting I’ll write about lambdas and their use with Intel Threading Building Blocks.

Hello, Lambdas, version 1:

template<typename F> 

void Eval( const F& f ) {
    f();
}
void foo() {
    Eval( []{printf("Hello, Lambdas\n");} );
}

Hello, Lambdas, version 2:

void bar() {
    auto f = []{printf("Hello, Lambdas\n"); };
    f();

	}


Lambdas, my quick reference guide:

Compilers that support lambdas will create a unique anonymous functor type for each lambda expression. Lambda expressions are useful as arguments to template functions or with C++0x auto keyword.

Here are some valid uses of lambda to look at before getting into the formal definition:

[&](float x){sum+=x;}

[&]{return *p++;}

[=](float x) {return a*x+b;}

[](float x, float y)->float {

    if(x<y) return x;
    else return y;

	}

A lambda function starts with ‘[‘ and is specified as:

[capture_mode] (formal_parameters)mutable throw() -> return_type {body}

Which is broken down as follows:

[capture_mode]

[&] means captured variables are by-reference, changes will affect variables from outside the body (the surrounding scope when the lambda was defined) when modified in the body
[=]
means captured variables are by-value, changes to them in the body will not affect the value outside the body (being allowed to change the value inside the body does require the 'mutable' keyword be used)
[]   means no capture of variables from other scope(s), any reference to a variable not passed in as a parameter or otherwise defined in the code body will be flagged as undefined by the compiler (perhaps with a polite reminded that you can’t access variables in a lambda from other scopes without a capture specified).

You can specify variables to differ from the default you specify, by naming them in the capture. Therefore a capture of [&,=total] says to capture variables by reference except to capture variable total by value. You can let the default be no capture by specifing variables all explicitly such as [&foo,&bar].

(formal_parameters)can be omitted if there are no parameters and the return type is implicit. Default arguments, variable length argument lists and unnamed parameters are not allowed – otherwise the parameter list is basically like any other.

mutable: An optional keyword "mutable" is required if you want the body to be allowed to modify captured variables that were captured 'by value.' The compiler will issue an error otherwise if changing a capture-by-value variable is attempted.

throw(): A lambda expression may optionally include an exception specification after the parameter list and before the return type specification. The parameter list is necessary if there is an exception specification.

The following lambda expressions specify that they do not throw exceptions:


[](int x) throw() -> bool {return x*7==0;}

[]() throw() {return rand();}

return_typecan be omitted if return type is void or code is simply “return expr;”

{body} is simply a block of code.

If my quick reference is not enough – you can see the standards paper with all the details http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2914.pdf (starting page 87.)

For more complete information about compiler optimizations, see our Optimization Notice.

10 comments

Top
Shirly C.'s picture

Very very thanks for sharing these helpful tips here. That's really very nice of you. Very simple and easy coding techniques. Happy coding... :)

Ryan Newton (Intel)'s picture

Very helpful! One thing that might also help would be a simple example of how to store lambdas (closures) in data structures. Getting that to typecheck has befuddled me in the past.

anonymous's picture

I am wondering how many programmers will be able to take advantage of the new, even more humungus, standard.

I am also wondering if, after learning all this crap, there is anything left to learn coding.

The outcome will be easy to spot: apparently, some other pals insist to use ANSI C (the "smaller and cleaner language" up to Bjarne) to scale on parallel architectures.

Maybe C is "smaller and cleaner" enough to leave more juice in the coders' mind.

That will be an interesting experiment.

anonymous's picture

[&](float x){sum+=x;}
[&]{return *p++;}
[=](float x){return a*x+b;}

^ |--- why C++ just got even more anal.

anonymous's picture

figured out:

-std=c++0x
Chuck

anonymous's picture

How to compile these code samples?

I tried both latest g++ (4.4.1) and icc (11.1) on Linux32 (Debian4-x), they both fail to compile the lambda syntax.

What compiler should I use?
and/or
what flag should I set?

Thank you
Chuck

James R.'s picture

I've fixed the issues noted. Thank you.
Yes, I got clever and changed "Hello, World" to "Hello, Lambda" in foo() just before I posted and I did a cut-n-paste to bar() leaving an extra parenthesis after painstakingly copying my real working code into the blog before this attempt at being clever. As for value and total - it was a late night. Many thanks for the feedback.
I also updated the link to the latest standard, and added "mutable" explanation to my quick reference. So much for keeping it short!

anonymous's picture

"[&,=value] says to capture variables by refernce except to capture variable total by value"

Shouldn't that be [&,=total]? (and "refernce" is spelled wrong)

anonymous's picture

Thanks for that. Noticed a small typo in the void bar() function.

auto f = []{printf("Hello, Lambdasn");} );
should be:
auto f = []{printf("Hello, Lambdasn");};

anonymous's picture

I just assume there is a typo on line 14.

Add a Comment

Have a technical question? Visit our forums. Have site or software product issues? Contact support.