5
votes

Out of a window procedure, I'm writing a switch statement using self-executing lambdas, like this:

LRESULT CALLBACK proc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg)
    {
        case WM_CREATE: return [&](WPARAM wp, LPARAM lp) {
            do_something(wp, lp);
            return 0;
        }(wp, lp);

        case WM_SIZE: return [&](HWND hWnd) {
            do_another_thing(hWnd);
            return 0;
        }(hWnd);
    }
    return DefWindowProc(hWnd, msg, wp, lp);
}

I believe compilers are free to optimize it pretty much the way they want, but generally speaking, would a compiler add much boilerplate code to this, comparing to not using these lambdas?

Could a compiler detect the redundant lambdas and remove them?

2
Just from curiosity: why? I mean what advantage do you seek from self-executing anonymous lambdas? You can't reuse them (because they are anonymous, not referenced in any other place), so...?Adrian Colomitchi
I think compiler would simply replace return []() {... return x; }() with {... return x; }. Seems trivial optimization. However this Q is more of an "opinion based", as there is no deterministic ansr.iammilind
@AdrianColomitchi Frivolous reason: because they are beautifully collapsed in Visual Studio IDE editor.rodrigocfd
@Rodrigo you can just put them in {...} to get outlining to work. No need for this silliness.3Dave
@Rodrigo Anyway I still would like to know the implications of such lambda constructs. The biggest implication I can think of is that your future code maintainers will wonder why the code is written that way and what they're missing (how it behaves differently from the obvious solution).Mark B

2 Answers

6
votes

Optimization questions like this don't have a definite answer in the sense that the optimizer of a compliant compiler can do many, many things. However, in this case most modern optimizers are almost certainly going to inline the lambda, and generate the same assembly whether or not you use the lambda. Because lambdas have a unique type, the compiler can inline easily. Because the lambda is declared and immediately used and never assigned (a more common name is "immediately invoked/evaluated lambda instead of "self executing"), the compiler knows it can only be called once. So typically it will decide to inline.

To be sure, you can look at some assembly: https://godbolt.org/g/QF6WmR. As you can see, the generated assembly in this particular example is identical, but obviously it does not prove the general case.

In general, lambdas are considered low or zero cost abstractions in C++, if you think a lambda makes for the cleanest code then use one. If you need to you can always quickly verify the assembly is the same. Your reason for using the lambda that way is a bit unusual though; I wouldn't really consider code folding to be a good reason. A more common reason to use immediately evaluated lambdas is to be able to use const in situations where otherwise you can't:

int x;
try {
    x = foo();
}
catch (const ExceptionType& e) {
    x = bar();
} 

vs

const auto x = [] () {
    try {
        return foo();
    }
    catch (const ExceptionType& e) {
        return bar();
    }
}();

To persist x in the outside scope in traditional C++ code, we have to declare it first and then assign to it. By using a lambda that returns the value we want, we can declare and assign x at the same time, allowing it to be const.

4
votes

The question is a bit odd. The compiler doesn't "remove" the lambdas, because the lambdas are in your source code, and the compiler doesn't modify your source code. What it does is emit machine code that produces the behaviour of the program you expressed in source code.

The compiler is free to emit as much or as little machine code as it likes as long as the result behaves the way that your program expresses.

A compiler certainly does not have to emit separate function bodies and jumps/calls between them if it can inline all the code into one place, and that is a commonly applied optimization.