Skip to content

std::function

概述

std::function<R(Args...)> 是 C++11 引入的类型擦除包装器,用于统一存储任意可调用对象(函数指针、lambda、std::bind 表达式、函数对象)。它是回调机制和函数式编程模式的核心组件。

头文件

cpp
#include <functional>

语法

cpp
std::function<R(Args...)> f;

// 示例
std::function<int(int, int)> add = [](int a, int b) { return a + b; };
std::function<void()> callback = []() { std::cout << "done\n"; };

可包装的类型

类型示例
函数指针int(*)(int, int)
Lambda[](int x) { return x * 2; }
std::bind 表达式std::bind(add, _1, 10)
函数对象结构体重载 operator()
成员函数指针&Class::method(需绑定 this

代码示例

基本用法

cpp
#include <functional>
#include <iostream>

void execute(std::function<int(int, int)> op, int a, int b) {
    std::cout << "Result: " << op(a, b) << "\n";
}

int main() {
    execute([](int a, int b) { return a + b; }, 3, 4);  // 7
    execute([](int a, int b) { return a * b; }, 3, 4);  // 12
}

排序自定义比较器

cpp
#include <algorithm>
#include <functional>
#include <vector>

int main() {
    std::vector<int> nums = {5, 2, 8, 1, 9, 3};

    std::function<bool(int, int)> desc = [](int a, int b) {
        return a > b;
    };

    std::sort(nums.begin(), nums.end(), desc);
    // nums: {9, 8, 5, 3, 2, 1}
}

回调模式

cpp
#include <functional>
#include <string>
#include <iostream>

class Button {
    std::function<void()> onClick_;
public:
    void setOnClick(std::function<void()> callback) {
        onClick_ = callback;
    }
    void click() {
        if (onClick_) onClick_();
    }
};

int main() {
    Button btn;
    int count = 0;
    btn.setOnClick([&count]() {
        count++;
        std::cout << "Clicked " << count << " times\n";
    });
    btn.click();  // Clicked 1 times
    btn.click();  // Clicked 2 times
}

存储不同类型

cpp
#include <functional>
#include <iostream>

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

struct Multiplier {
    int factor;
    int operator()(int x) const { return x * factor; }
};

int main() {
    std::function<int(int, int)> f1 = add;
    std::function<int(int)> f2 = Multiplier{5};

    std::cout << f1(3, 4) << "\n";  // 7
    std::cout << f2(6) << "\n";     // 30
}

性能考虑

方面说明
堆分配小型捕获可能内联,大捕获触发堆分配
虚分发调用通过内部虚函数,有间接调用开销
与函数指针对比函数指针零开销,std::function 有包装成本
与模板对比模板完全内联,std::function 有类型擦除成本

经验法则:若性能是关键路径,优先使用模板。若需要运行时多态或类型擦除,使用 std::function

std::function vs 函数指针 vs 模板

特性函数指针std::function模板
捕获状态不能
类型擦除
性能开销中等零(内联)
运行时多态
适用场景纯函数回调/策略高性能泛型代码

注意事项与陷阱

空 std::function

cpp
std::function<int()> f;
// f();  // 未定义行为,抛出 std::bad_function_call

if (f) {
    f();  // 安全
}

移动语义

std::function 支持移动语义,大捕获的 lambda 移动比拷贝更高效:

cpp
std::function<void()> f = [big_data = std::move(data)]() {
    // 使用 big_data
};

类型擦除的隐式成本

std::function 会在内部存储一个指向捕获数据的指针。即使 lambda 为空捕获,也有间接调用开销。对于简单的函数指针场景,直接使用函数指针更高效。

编译器支持

编译器最低版本
GCC4.4+
Clang3.1+
MSVC2012+(VS 11.0)

基于 MIT 许可发布