loading...

Modern C++: Lambdas

delta456 profile image Swastik Baranwal Updated on ・3 min read

Following my series from less known features of Modern C++.

Lambdas

Lambdas are anonymous functions which are un-named functions as they are mostly needed for High Order Functions and for small purposes where they don't need much importance to be named. Lambdas were introduced in C++11 and heavily improved in the new standards.

Syntax

[capture list](parameter list) -> return type (optional) {
  function body
}
  • Capture List: Specifies how the value will be captured in the scope.
  • Parameter List: Parameters required for the function
  • Return Type (Optional) : The return type of the function.
  • Function Body: Body of the function.

Basic Examples

#include <iostream>

int main() {

 int add = [](int a){ return 2 + 3; }(); // using lambda and then storing the value

 [](){ std::cout<< "Caliing like this also works" << std::endl; }(); 

 auto callback = [](auto a, auto b) { 
        a == b;
  }; // using a label and then using it for various purposes
}

Capture List

A lambda can introduce new objects in its body and can also access or capture objects from the surrounding scope. A lambda begins with the capture clause which specifies the objects that are captured and whether the capture is by value or by reference. Objects that have the ampersand (&) prefix are accessed by reference and objects that do not have it are accessed by value.

An empty capture list [] means that there are no variables captured. If the user wants all variables to be captured by reference then one should use [&] or pass by value then use [=]. If one wants some variable to be captured by reference or value then they should do [foo, &var].

The following are valid:

[&var, foo] // var is captured by reference and foo is passed by value.
[&, factor] // only factor is captured by value here.
[=, &total] // only total is passed by reference.
[] // no objects are passed.

Parameter List

Like functions, parameters are optional for lambdas.

#include <iostream>

int main() {

auto add = [](int a, int b) -> int {
      return a + b;
  };

auto print = []() {
  std::cout << "Printing from lambda." << std::endl;
};

std::cout << add(5, 5) << std::endl;
std::cout << print() << std::endl;
}

In this example we have add() lambda which takes parameter and print() lambda which doesn't take.

Since C++ 14, we can now use auto for type deceleration which can be helpful for combating more problems.

#include <iostream>

int main() {

 auto add = [](auto a, auto b) {
      return a + b;
   };

 std::cout << add(5, 5) << std::endl; // for int
 std::cout << add(24.567, 456.7) << std::endl; // for float
 std::cout << add("generic", "lambdas") << std::endl; // for std::string
}

mutable Specifier

mutable allows objects captured by value to be modified and use it's non-constant methods/functions in the specific lambda function.

#include <iostream>

int main() {

 int var = 5;

 auto change = [var]() mutable { var = 10; std::cout << var << std::endl;  };
 change();

 std::cout << var << std::endl; // var is 5
} 

Examples

Nested Lambdas

A simple program which takes input and then determines if they are negative or not.

#include <iostream>

int main() {

    auto is_negative = [](int x) { return [](int y) { return y + 2; }((5) + x) <  0; }(7);
    std::cout << is_negative;

}

High Order Functions

A simple program which takes a function to sort an array in the reverse order.

#include <iostream>
#include <algorithm>
#include <array>

int main() {

    std::array<int, 9> arr = {4, 6, 7, 5, 8, 0, 2, 3, 7 };
    std::sort(begin(arr), end(arr), [](int a, int b){ return a < b;});

    for (auto& i : arr) {
        std::cout << i << " ";
    }

}

Lambdas with Templates

A program which uses templates and lambdas together.

#include <iostream>
#include <algorithm>
#include <array>

template<typename T>
void multi_by_two(std::array<T, 9>& arr) {
  std::for_each(arr.begin(), arr.end(), [](T& a){a *= 2;});
}

int main() {

    std::array<int, 9> arr = {4, 6, 7, 5, 8, 0, 2, 3, 7 };
    add_by_two(arr);

    for (auto& i : arr) {
        std::cout << i << " ";
    } 
}

Code

All the code used in this article is available in this repo.

If someone has any doubt or something is misleading then do inform me by commenting below.

Discussion

markdown guide
 

[=, &total] please explain what the = does on this line?

 

It passes all objects by value.