CS253: Software Development with C++

Spring 2023

Lambda Functions

Show Lecture.LambdaFunctions as a slide show.

CS253 Lambda Functions

Lambda

λ

This is the Greek letter lambda.

In C++, it refers to an anonymous function, an unnamed function, a function literal.

Functions

A function

Here’s a boring ordinary function:

bool odd(int n) { return n & 0b1; }

int main() {
    cout << odd(42) << ' ' << odd(43);
}
0 1

The 0b prefix indicates a binary constant. Sure, 1, 01, or 0x01 would also work, but 0b1 stresses that it’s a bitmask.

Boolean values are displayed as 0 and 1 by default, unless you use cout << boolalpha.

Pointer to a function

bool odd(int n) { return n & 0b1; }

int main() {
    bool (*p)(int) = odd;
    cout << (*p)(42) << ' ' << p(43);
}
0 1

auto is your friend

bool odd(int n) { return n & 0b1; }

int main() {
    auto p = odd;
    cout << (*p)(42) << ' ' << p(43);
}
0 1

🧙 Even though C++ wizards understand bool (*p)(int) = odd; just fine, we realize that auto sure made that declaration easier!

There must be a better way.

cout << 355/113.0;              // easy as
3.14159

int numerator=355;
float denominator=113.0;
cout << numerator/denominator;  // tedious
3.14159

Trailing return type

There are two ways to declare a function return type:

bool odd_and(int n) { return n & 0b1; }
auto odd_mod(int n) -> bool { return n % 2 != 0; }

int main() {
    cout << odd_and(12) << ' ' << odd_mod(13);
}
0 1

Patience—neither of these are lambda functions, because they have names.

Deduced Return Type

If the trailing return type is not given, it is deduced:

bool odd_and(int n) { return n & 0b1; }
auto odd_mod(int n) { return n % 2 != 0; }

int main() {
    cout << odd_and(12) << ' ' << odd_mod(13);
}
0 1

This use of auto does not indicate any sort of run-time flexibility. Instead, it instructs the compiler to figure it out at compile time, the same as auto answer=42; figures out the type of answer from the type of 42. In neither case is there any run-time flexibility.

The return type of odd_mod is not auto, it’s the actual type that is returned.

Deduced Return Type

However, the return type must be unambiguous:

auto delta(bool flag) {
    if (flag)
        return 5;
    return 6.7;  // 🦡
}

int main() {
    cout << delta(true);
}
c.cc:4: error: inconsistent deduction for auto return type: ‘int’ and then 
   ‘double’

λ-expressions

auto p = [](int n) -> bool { return n & 0b1; };
cout << p(42) << ' ' << p(43);
0 1

λ-expressions

The return-type may be deduced, if omitted:

auto p = [](int n) { return n & 0b1; };
cout << p(42) << ' ' << p(43);
0 1
What is the return-type of the lambda-expression pointed to by p?
  • n is an int, 0b1 is an int, so n & 0b1 is an int.
  • Therefore, the return-type is int.
  • An int works as well as a bool in this context.
    • Before C had bool, it used int as a boolean type.

Generic λ-expressions

Even the arguments can be auto:

auto twice = [](auto v) { return v + v; };

cout << twice(3)       << '\n'
     << twice(2.34)    << '\n'
     << twice("Jack"s) << '\n'
     << twice('!')     << '\n';
6
4.68
JackJack
66

No arguments

If no arguments are needed, the () can be omitted:

auto unique_id = [] { return getpid(); };
cout << unique_id();
3108632

Of course, this example could be accomplished with a simple pointer:

auto unique_id = getpid;     // no parens
cout << unique_id();
3108633

Use