C/C++ Arena

Step 5 of 6

Captures

The lambdas so far used only their own parameters. Often you need a value from outside the lambda, like a threshold the user typed in. A lambda can't see local variables automatically; you have to capture them in the []:

Capture Meaning
[x] copy of x
[&x] reference to x
[=] copy everything used
[&] reference everything used
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> names = {"ana", "bartholomew", "cy", "delphine", "ed"};
    size_t max_len = 3;

    std::vector<std::string> shorts;
    std::copy_if(names.begin(), names.end(), std::back_inserter(shorts),
                 [max_len](const std::string& s) { return s.size() <= max_len; });
    for (const auto& s : shorts) std::cout << s << " ";
    std::cout << "\n";

    int letters = 0;
    std::for_each(names.begin(), names.end(), [&letters](const std::string& s) { letters += (int)s.size(); });
    std::cout << letters << " letters\n";

    int bonus = 10;
    auto add_bonus = [bonus](int x) { return x + bonus; };
    bonus = 1000;                          // too late: the lambda holds its own copy
    std::cout << add_bonus(5) << "\n";
}
ana cy ed 
26 letters
15

Copy or reference?

back_inserter

std::copy_if(first, last, out, pred) copies the matching elements to out. Since you don't know in advance how many will match, you can't pre-size the result. std::back_inserter(v) (from <iterator>) is an output iterator that calls v.push_back(...) for every element written, so the vector grows as needed.

Common mistakes

Your turn: write std::vector<int> above(const std::vector<int>& v, int threshold) that returns the elements greater than threshold, keeping their order. Use std::copy_if with std::back_inserter(out) and a lambda that captures threshold.

Previous: accumulate and transform Next: Erase with a condition