Summary of C++ std::function Usage

<span>std::function</span> is a generic function wrapper introduced in C++11 (defined in the <span><functional></span> header), which can store, copy, and invoke any callable object (functions, lambda expressions, function pointers, functors, bind expressions, etc.), making it a core tool for callback mechanisms, event handling, and other scenarios.

Basic Usage: Definition and Invocation

<span>std::function</span> has a template parameter for the function signature (return type + parameter list), formatted as:

std::function<return_type(parameter_type1, parameter_type2, ...)>

Example: Wrapping Different Types of Callable Objects

#include <functional>#include <iostream>// 1. Regular functionint add(int a, int b){    return a + b;}// 2. Functor (struct that overloads operator())struct Multiply{    int operator()(int a, int b) { return a * b; }};int main(){    // Wrap regular function    std::function<int(int, int)> func1 = add;    // Output: 5    std::cout << func1(2, 3) << std::endl;    // Wrap functor    std::function<int(int, int)> func2 = Multiply{};    // Output: 6    std::cout << func2(2, 3) << std::endl;    // Wrap lambda expression    std::function<int(int, int)> func3 = [](int a, int b) { return a - b; };    // Output: 3    std::cout << func3(5, 2) << std::endl;    // Wrap function pointer    int (*sub_ptr)(int, int) = [](int a, int b) { return a - b; };    // Convert lambda to function pointer (when not capturing)    std::function<int(int, int)> func4 = sub_ptr;    // Output: 2    std::cout << func4(5, 3) << std::endl;    return 0;}

Core Feature: Storing and Passing Callable Objects

<span>std::function</span>’s core value is to unify different types of callable objects, making it easier to store and pass (e.g., as function parameters, return values, container elements).

1. As Function Parameters (Callback Function Scenario)

// Accept std::function as a parameter to implement a generic callbackvoid process(int a, int b, std::function<int(int, int)> op) {    std::cout << "Result: " << op(a, b) << std::endl;}int main() {    // Regular function as callback    process(10, 5, add);       // Functor as callback    process(10, 5, Multiply{});      // Lambda as callback    process(10, 5, [](int a, int b) { return a / b; });     return 0;}

2. As Function Return Values

// Return different operation functions based on conditionsstd::function<int(int, int)> GetOperator(char op){    switch (op)    {    case '+':        return add;    case '*':        return Multiply{};    case '-':        return [](int a, int b) { return a - b; };    default:        return [](int, int) { return 0; };    }}int main() {    auto op = GetOperator('*');    // Output: 12    std::cout << op(3, 4) << std::endl;      return 0;}

3. As Container Elements

#include <vector>int main() {    std::vector<std::function<int(int)>> funcs;    // Multiply by 2    funcs.push_back([](int x) { return x * 2; });   // Add 10    funcs.push_back([](int x) { return x + 10; });  // Square    funcs.push_back([](int x) { return x * x; });   int x = 3;    for (auto&amp; f : funcs)     {        std::cout << f(x) << " ";  // Output: 6 13 9    }    return 0;}

4. Combining <span>std::bind</span> to Bind Parameters

<span>std::function</span> can be used with <span>std::bind</span> to fix some parameters and return a new callable object.

#include <functional>// Original function: 3 parametersint sum(int a, int b, int c){    return a + b + c;}int main() {    // Bind the first two parameters to 10 and 20, keeping only the last parameter    // std::placeholders::_n indicates "the nth unbound parameter", which must be passed during the call.    auto bindFunc = std::bind(sum, 10, 20, std::placeholders::_1);    // Wrap the bound function with std::function (now only 1 parameter is needed)    std::function<int(int)> func = bindFunc;    // 10 + 20 + 30 = 60    std::cout << func(30) << std::endl;      return 0;}

5. Binding Member Functions

<span>std::function</span> can wrap class member functions by binding to specific objects or pointers.

#include <functional>#include <iostream>class Math{public:    int pow(int a, int b)    {        // Member function        int res = 1;        for (int i = 0; i < b; ++i)        {            res *= a;        }        return res;    }};int main(){    Math m;    // Wrap member function: need to pass object pointer + member function address    // The first implicit parameter of a member function is the this pointer, so binding requires explicit passing of the object (or pointer).    std::function<int(int, int)> func = std::bind(&amp;Math::pow, &amp;m,                                                  std::placeholders::_1,                                                  std::placeholders::_2);    // 2^3 = 8    std::cout << func(2, 3) << std::endl;     return 0;}

Summary

1. Main Usage

<span>std::function</span> is the “universal container” for unifying callable objects in C++, with main usages including:

  • Wrapping functions, lambdas, functors, and other callable objects;
  • Passing as parameters (callback functions), returning as values (function factories), and as container elements;
  • Combining <span>std::bind</span> for parameter binding and member functions;
  • Be cautious of null state checks and object lifetimes.

2. Considerations

  1. Performance Overhead: <span>std::function</span> implements type erasure internally, resulting in slight performance loss during calls (slower than direct function pointer calls), but usually negligible.
  2. Lifetime Management: If wrapping a lambda that captures a reference or a <span>std::bind</span> expression that binds a local object, ensure the lifetime of the referenced object exceeds that of <span>std::function</span>, otherwise it may lead to undefined behavior.
  3. Non-Copyable Callable Objects: <span>std::function</span> requires the stored callable objects to be copyable; if the object is non-copyable (e.g., <span>std::unique_ptr</span> captured in a lambda), it cannot be stored (partially supported move semantics since C++17).
  4. Compatibility with Lambdas: Non-capturing lambdas can be implicitly converted to function pointers, while capturing lambdas can only be wrapped by <span>std::function</span>.

Leave a Comment