Leveraging Lambda Expressions and Function Wrappers in C++11

Lambda Expressions

A lambda expression in C++11 follows the syntax: [capture-list] (parameters) mutable -> return-type { statement }.

  • Capture List ([capture-list]): Defines variables accessible within the lambda. It must be present and is used by the compiler to identify a lambda. Variables can be captured by value or by reference.

    • [v]: Captures variable v by value.
    • [=]: Captures all variables from the enclosing scope by value, including this.
    • [&v]: Captures variable v by reference.
    • [&]: Captures all variables from the enclosing scope by reference, including this.
    • [this]: Captures the current this pointer by value.
  • Parameter List (parameters): Optional. Matches standard function parameters. Can be omitted if no arguments are needed.

  • mutable: Allows modification of captured variables even if they were captured by value. This keyword requires the parameter list to be explicitly writtan, even if empty.

  • Return Type (-> return-type): Optional. The compiler can deduce the return type using auto. Explicit declaration is only necessary when the return type cannot be inferred.

  • Function Body {statement}: Required. Contains the logic executed when the lambda is invoked. Accesses both parameters and captured variables.

Note: The capture list and function body are mandatory, while other parts may be omitted. The minimal valid lambda is [] {}.

Example Usage

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> nums = {1, 3, 5, 7, 2, 4, 6, 8};
    int x = 3, y = 4;

    // Capture by value
    auto add_three = [=]() { return x + 3; };
    std::cout << add_three() << "\n";

    // Capture by reference
    auto modify_y = [&](int val) { y += val; };
    modify_y(10);
    std::cout << "x: " << x << ", y: " << y << "\n";

    // Full lambda with return type
    auto sum_with_x = [=, &y](int z) -> int { return y += x + z; };
    std::cout << sum_with_x(10) << "\n";

    // Mutable capture
    int num = 10;
    auto double_and_add = [num](int input) mutable {
        num *= 2;
        return input + num;
    };
    std::cout << double_and_add(10) << "\n";

    // Sorting with lambda
    std::sort(nums.begin(), nums.end(), [](int a, int b) { return a > b; });
    for (const auto& n : nums) {
        std::cout << n << " ";
    }
    std::cout << "\n";

    return 0;
}

Lambda expressions are essentially unnamed function objects. The compiler generates a unique class for each lambda, overloading operator() to enable invocation. Despite identical bodies, lambdas have distinct types and cannot be assigned to one another.


Function Wraper (std::function)

std::function is a general-purpose polymorphic function wrapper that enables uniform handling of various callable entities such as function pointers, functors, and lambdas.

#include <functional>
#include <iostream>

// Regular function
double divide_by_two(double d) {
    return d / 2;
}

// Functor
struct Divider {
    double operator()(double d) const {
        return d / 3;
    }
};

// Generic wrapper function
template <class F, class T>
T execute(F func, T arg) {
    static int call_count = 0;
    std::cout << "Call #" << ++call_count << " (address: " << &call_count << ")\n";
    return func(arg);
}

int main() {
    // Using function pointer
    std::function<double(double)> wrapper1 = divide_by_two;
    std::cout << execute(wrapper1, 11.11) << "\n";

    // Using functor
    std::function<double(double)> wrapper2 = Divider();
    std::cout << execute(wrapper2, 11.11) << "\n";

    // Using lambda
    std::function<double(double)> wrapper3 = [](double d) { return d / 4; };
    std::cout << execute(wrapper3, 11.11) << "\n";

    return 0;
}

For member functions, special care is required:

int subtract(int a, int b) { return a - b; }

class Calculator {
public:
    static int add_static(int a, int b) { return a + b; }
    double subtract_member(double a, double b) { return a - b; }
};

int main() {
    // Non-member function
    std::function<int(int, int)> f1 = subtract;
    std::cout << f1(10, 5) << "\n";

    // Static member function
    std::function<int(int, int)> f2 = &Calculator::add_static;
    std::cout << f2(1, 1) << "\n";

    // Non-static member function
    Calculator calc;
    std::function<double(Calculator*, double, double)> f3 = &Calculator::subtract_member;
    std::cout << f3(&calc, 10, 5) << "\n";

    std::function<double(Calculator, double, double)> f4 = &Calculator::subtract_member;
    std::cout << f4(Calculator(), 10, 5) << "\n";

    return 0;
}

std::bind – Parameter Binding

std::bind allows fixing certain arguments of a functon and rearranging parameter order.

Reordering Parameters

int difference(int a, int b) { return a - b; }

int main() {
    int x = 10, y = 20;
    std::cout << difference(x, y) << "\n"; // Output: -10

    auto reversed = std::bind(difference, std::placeholders::_2, std::placeholders::_1);
    std::cout << reversed(x, y) << "\n"; // Output: 10

    return 0;
}

Fixing Arguments

class MathOp {
public:
    double compute(double a, double b) { return a - b; }
};

int main() {
    // Bind two arguments
    std::function<double(double, double)> op1 = std::bind(&MathOp::compute, MathOp(), std::placeholders::_1, std::placeholders::_2);
    std::cout << op1(2.0, 3.0) << "\n"; // Output: -1.0

    // Fix second argument
    std::function<double(double)> op2 = std::bind(&MathOp::compute, MathOp(), std::placeholders::_1, 20.0);
    std::cout << op2(2.0) << "\n"; // Output: -18.0

    return 0;
}

std::bind is especially useful when creating function objects with pre-bound parameters, enabling partial application and reusable callbacks.

Tags: C++11 lambda function Bind Callable

Posted on Mon, 26 Oct 2026 16:26:16 +0000 by animuson