Skip to content

Wiki

std::function

About 10 min read

Existing English translations were reused. 1 current source blocks remain in Simplified Chinese, without triggering paid translation.

1.What problem does this section solve?

Ordinary functions, function pointers, lambdas, and function objects can all be "called," and they are collectively referred to as callable objects. However, their concrete types are not the same:

  • A regular function has a function type.
  • A function pointer is a pointer type.
  • Each lambda has a distinct compiler-generated type.
  • A function object is a user-defined class type.

If you only call it once immediately, differing types are usually not a problem; but if you want to store the callback in a member variable, or put multiple different callbacks into the same container, you need a unified type.

std::function It is the general-purpose callable object wrapper provided by the standard library.

2.What is this feature?

std::function<返回值(参数列表)> Any callable object matching the signature can be saved.

For example, std::function<int(int, int)> means: save one that can be called with two int and returns int callable object.

3.C++ Standard Edition

std::function Provided starting from C++11, requires the header file <functional>.

4.Common scenarios

Scenario Is it suitable?std::function Reason
Calling a callback once immediately inside a function Not necessarily Template parameters are usually more lightweight
Storing a callback in a class member variable Suitable Member variables need a stable type
vectorStoring multiple different lambdas Suitable Container elements must all be of the same type
A small function in a high-frequency performance hotspot Be cautious std::functionThere is type erasure overhead
Storing only captureless functions A function pointer also works But a function pointer cannot store a capturing lambda

5.Example code

5.1.Example 1: Uniformly storing callable objects of different types

#include <functional>
#include <iostream>

int add(int a, int b)
{
    return a + b;
}

struct Multiply
{
    int operator()(int a, int b) const
    {
        return a * b;
    }
};

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    // std::function 可以保存普通函数、lambda 或函数对象。
    std::function<int(int, int)> op;

    op = add;
    std::cout << "add: " << op(3, 4) << "\n";

    int (*function_pointer)(int, int) = add;
    op = function_pointer;
    std::cout << "function pointer: " << op(5, 6) << "\n";

    op = [](int a, int b) {
        return a - b;
    };
    std::cout << "lambda: " << op(10, 3) << "\n";

    op = Multiply{};
    std::cout << "function object: " << op(7, 8) << "\n";

    return 0;
}

Running result:

add: 7
function pointer: 11
lambda: 7
function object: 56

5.2.Example 2: Passing a callback as a std::function parameter

In this example,calculate does not care whether what is passed in is an ordinary function or a lambda; it only requires the signature to be int(int, int).

#include <functional>
#include <iostream>

int add(int a, int b)
{
    return a + b;
}

// std::function 可以保存普通函数、lambda 或函数对象。
int calculate(int a, int b, const std::function<int(int, int)>& op)
{
    return op(a, b);
}

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    int x = 10;
    int y = 5;

    int r1 = calculate(x, y, add);
    std::cout << "add result = " << r1 << "\n";

    int r2 = calculate(x, y, [](int a, int b) {
        return a * b;
    });
    std::cout << "multiply result = " << r2 << "\n";

    int offset = 100;
    int r3 = calculate(x, y, [offset](int a, int b) {
        return a + b + offset;
    });
    std::cout << "with offset result = " << r3 << "\n";

    return 0;
}

Running result:

add result = 15
multiply result = 50
with offset result = 115

5.3.Example 3: Save the callback to a class member variable

A function pointer cannot store a lambda with captures;std::function it can, so it is very suitable for storing event callbacks.

#include <functional>
#include <iostream>
#include <string>
#include <utility>

class Button
{
    // std::function 可以保存普通函数、lambda 或函数对象。
    std::function<void()> on_click_;

public:
    void set_on_click(std::function<void()> callback)
    {
        on_click_ = std::move(callback);
    }

    void click() const
    {
        if (on_click_)
        {
            on_click_();
        }
        else
        {
            std::cout << "no callback\n";
        }
    }
};

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    Button button;

    button.click();

    std::string name = "Save";
    int count = 0;

    button.set_on_click([name, &count]() {
        ++count;
        std::cout << name << " clicked, count = " << count << "\n";
    });

    button.click();
    button.click();

    return 0;
}

Running result:

no callback
Save clicked, count = 1
Save clicked, count = 2

Here capture by value name and capture by reference count. Since both button and count are in main and count lives longer than the callback invocation, this example is safe. In real asynchronous scenarios, lifecycle handling must be more careful when storing callbacks.

5.4.Example 4: Put multiple different callbacks into the same container

Each Lambda has a different type and cannot be placed directly into the same vector. After using std::function<void()> they then have a unified type.

#include <functional>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    // std::function 可以保存普通函数、lambda 或函数对象。
    // vector 是动态数组,元素数量可以在运行时变化。
    std::vector<std::function<void()>> tasks;

    int total = 0;
    std::string label = "task";

    tasks.push_back([label]() {
        std::cout << label << " A\n";
    });

    tasks.push_back([&total]() {
        total += 10;
        std::cout << "add 10, total = " << total << "\n";
    });

    tasks.push_back([&total]() {
        total *= 2;
        std::cout << "double, total = " << total << "\n";
    });

    for (const auto& task : tasks)
    {
        task();
    }

    std::cout << "final total = " << total << "\n";

    return 0;
}

Running result:

task A
add 10, total = 10
double, total = 20
final total = 20

5.5.Example 5: Template parameters can also accept callbacks when invoked only immediately

std::functionThe advantage is "saving and unifying types." If it is only called immediately and does not need to be saved, function templates are usually more lightweight.

#include <iostream>

template<typename Callback>
void repeat(int times, Callback callback)
{
    for (int i = 0; i < times; ++i)
    {
        callback(i);
    }
}

int main()
{
    // 程序从 main 函数开始执行,下面的语句会按顺序运行。
    repeat(3, [](int i) {
        std::cout << "i = " << i << "\n";
    });

    // 返回 0 表示程序正常结束。
    return 0;
}

Running result:

i = 0
i = 1
i = 2

6.Key syntax explanation

写法 含义 注意事项
std::function<void()> 保存无参数、无返回值的回调 常用于按钮、定时器、任务队列
std::function<int(int, int)> 保存两个 int 参数、返回 int 的可调用对象 签名必须匹配
if (callback) 判断 std::function 是否为空 空回调不能直接调用
std::move(callback) 把传入的回调移动到成员变量 避免不必要拷贝
vector<std::function<void()>> 保存多个不同类型的回调 容器元素类型统一

7.The relationship between std::function and Lambda

Lambda is a callable object,std::function is a wrapper used to hold a callable object. They are not mutually substitutable.

Requirement Recommendation
Write a short logic inline Lambda
Store the callback as a variable or member std::function
Put multiple different lambdas into a container std::function
Called once and performance-sensitive Function template

8.Common Errors

  1. Empty std::function Direct call. Before calling, first check if (callback).
  2. Signature mismatch. For example, the callback requires int(int, int),so you cannot pass a callable object that accepts only one parameter.
  3. When saving the callback, the reference captured a local variable that has already been destroyed.
  4. Even if it only needs to be called temporarily once, also write the parameter as std::function,which incurs unnecessary overhead in performance-sensitive code.
  5. Assuming that a member function can be directly assigned to std::function<void(int)>. A non-static member function also requires an object; the next section will use std::bind and Lambda to solve this problem.

9.Usage Recommendations

  1. When you need to store a callback, use std::function.
  2. When you need to unify callbacks of different types, use std::function.
  3. When you only need to invoke a callback once immediately, prefer a template parameter.
  4. When storing callbacks, pay special attention to the lifetime of captured objects.
  5. Do not treat std::function as the sole answer for all callback scenarios; it is a tool for clarity and flexibility, and it also has a certain runtime overhead.

10.Summary

  • Callable objects include ordinary functions, function pointers, lambdas, function objects, etc.
  • std::function<返回值(参数...)> Use a uniform type to store callable objects with matching signatures.
  • std::function Suitable for storing callbacks, serving as member variables, and placing into containers.
  • An empty std::function cannot be called.
  • For callbacks that are only invoked temporarily once, template parameters are usually more lightweight.