C++14coreintermediate
Lambda Capture Initializers
C++14 · Modern Refined · Compiler flag: -std=c++14
Explanation
Lambdas can initialize captured variables with arbitrary expressions, including move semantics. This feature, also known as generalized lambda capture, enables transferring ownership of move-only types into closures and creating new variables scoped to the lambda.
Real-World Scenario
An asynchronous task scheduler needs to transfer ownership of a database connection handle into a lambda that will execute on a worker thread, ensuring no accidental sharing of the resource.
Quick Snippet
snippet.cpp
#include <memory>
#include <iostream>
#include <functional>
auto connection = std::make_unique<int>(42); // simulated DB handle
auto task = [conn = std::move(connection), attempt = 1]() mutable {
std::cout << "Handle: " << *conn << ", attempt: " << attempt++ << "\n";
};
task(); // Handle: 42, attempt: 1
task(); // Handle: 42, attempt: 2Full Example
lambda_capture_initializers.cpp
// CodeNebula - C++14 Example: Lambda Capture Initializers
// Compile: g++ -std=c++14 -Wall -Wextra -o example lambda_capture_initializers.cpp
// Demonstrates init captures (generalized lambda captures) in C++14. Allows
// creating new variables in the capture clause, including move captures.
// Real-world use: transferring ownership of unique_ptr into lambdas,
// capturing computed values, and creating self-contained closures.
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
int main()
{
// ------------------------------------------------------------------
// 1. Basic init capture - create a new variable in the capture
// ------------------------------------------------------------------
int x = 10;
auto add_offset = [offset = x + 5](int value) {
return value + offset;
};
std::cout << "=== Basic Init Capture ===" << std::endl;
std::cout << " x = " << x << ", offset = x + 5 = 15" << std::endl;
std::cout << " add_offset(100) : " << add_offset(100) << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 2. Move capture - transfer ownership of unique_ptr into lambda
// ------------------------------------------------------------------
auto ptr = std::make_unique<std::string>("Hello, C++14!");
std::cout << "=== Move Capture with unique_ptr ===" << std::endl;
std::cout << " Before move: ptr is "
<< (ptr ? "valid" : "null") << std::endl;
auto greet = [p = std::move(ptr)]() {
std::cout << " Inside lambda: " << *p << std::endl;
};
std::cout << " After move: ptr is "
<< (ptr ? "valid" : "null") << std::endl;
greet();
std::cout << std::endl;
// ------------------------------------------------------------------
// 3. Rename capture - capture under a different name
// ------------------------------------------------------------------
std::string name = "CodeNebula";
auto print_project = [project_name = name]() {
std::cout << " Project: " << project_name << std::endl;
};
std::cout << "=== Renamed Capture ===" << std::endl;
print_project();
std::cout << std::endl;
// ------------------------------------------------------------------
// 4. Capture expression result directly
// ------------------------------------------------------------------
std::vector<int> data = {1, 2, 3, 4, 5};
auto sum_above = [threshold = data.size() / 2](const std::vector<int>& v) {
int sum = 0;
for (auto val : v) {
if (static_cast<std::size_t>(val) > threshold) sum += val;
}
return sum;
};
std::cout << "=== Capture Computed Expression ===" << std::endl;
std::cout << " threshold (size/2) = " << data.size() / 2 << std::endl;
std::cout << " sum of elements > threshold: " << sum_above(data) << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 5. Mutable init capture with counter (stateful lambda)
// ------------------------------------------------------------------
auto counter = [count = 0]() mutable {
return ++count;
};
std::cout << "=== Mutable Init Capture (Counter) ===" << std::endl;
std::cout << " call 1: " << counter() << std::endl;
std::cout << " call 2: " << counter() << std::endl;
std::cout << " call 3: " << counter() << std::endl;
return 0;
}
/*
Expected output:
=== Basic Init Capture ===
x = 10, offset = x + 5 = 15
add_offset(100) : 115
=== Move Capture with unique_ptr ===
Before move: ptr is valid
Inside lambda: Hello, C++14!
After move: ptr is null
=== Renamed Capture ===
Project: CodeNebula
=== Capture Computed Expression ===
threshold (size/2) = 2
sum of elements > threshold: 12
=== Mutable Init Capture (Counter) ===
call 1: 1
call 2: 2
call 3: 3
*/
Run command
g++ -std=c++14 -Wall -Wextra -o example lambda_capture_initializers.cpp