Home Item 14 - initializer capture (English)
Post
Cancel

Item 14 - initializer capture (English)

Initializer Capture

In the previous article , we discussed that C++11 supports capturing variables in lambdas. Let’s review the code and rewrite it with deliberately long variable names.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

int main() {
    int x_thisIsAnExtremelyLongVariableName = 10;
    int y_thisIsAnExtremelyLongVariableName = 20;

    auto addXY = [x_thisIsAnExtremelyLongVariableName, y_thisIsAnExtremelyLongVariableName]() -> int {
        return x_thisIsAnExtremelyLongVariableName + y_thisIsAnExtremelyLongVariableName;
    };

    std::cout << "x_thisIsAnExtremelyLongVariableName + y_thisIsAnExtremelyLongVariableName = " << addXY() << std::endl;

    return 0;
}

The limitation here is that when capturing variables, you can only use the same variable names for capture. (When the variable names are unusual, they will appear in your lambda function.) Of course, this is not the main reason C++14 aims to improve this.

C++14 introduced a feature called initializer capture, which makes capturing variables in lambda expressions more flexible. It allows you to initialize variables in the capture list, which is particularly useful when you need to use temporary variables or computed values within the lambda expression.

Use Cases

There are four main scenarios:

Complex Expression Calculation

When you need to use complex calculation results within the lambda expression, you can use initializer capture to simplify the code.

1
2
3
4
5
int a = 27;
int b = 37;
auto lambda = [sum = a * b + 3](int x) {
    return sum + x;
};

Capturing Temporary Objects

When you need to use temporary objects (such as dynamically allocated memory, temporary strings, etc.) within the lambda expression, you can use initializer capture to ensure that these objects’ lifetimes cover the scope of the lambda expression.

Here’s an example using std::move. If you’re not familiar with it, you can refer to this article.

1
2
3
4
5
6
auto ptr = std::make_unique<int>(48);
auto lambda = [p = std::move(ptr)]() {
    std::cout << *p << std::endl;
};
lambda();

Renaming Variables

If you want to use different variable names within the lambda expression, you can achieve this through initializer capture.

For example, using the initial example

1
2
3
4
int x_thisIsAnExtremelyLongVariableName = 100;
auto lambda = [x = x_thisIsAnExtremelyLongVariableName](int y) {
    return x + y;
};

Capturing References

Although you can usually capture all external variable references using [&], sometimes you need to capture specific variable references. In such cases, initializer capture can also be useful.

1
2
3
4
5
6
int a = 45;
auto lambda = [&ref_a = a]() {
    ref_a += 17;
};
lambda();
std::cout << "a: " << a << std::endl;

Desktop View

These scenarios demonstrate the application of initializer capture in various contexts, providing a more flexible and concise programming approach.

☝ツ☝

This post is licensed under CC BY 4.0 by the author.

👈 ツ 👍