跳转到内容

C++stdfunction

来自代码酷

模板:Note

C++ std::function[编辑 | 编辑源代码]

std::function 是C++11标准库中引入的通用函数包装器,属于<functional>头文件。它提供了一种类型安全的方式存储、复制和调用任何可调用对象(函数、lambda表达式、函数对象、绑定表达式等)。

基本概念[编辑 | 编辑源代码]

std::function的核心特性:

  • 可以存储任何可调用目标(Callable Target),只要其签名与function的模板参数匹配
  • 提供统一的调用接口operator()
  • 当不含可调用目标时,调用会抛出std::bad_function_call异常
  • 多态函数包装器,运行时动态绑定具体实现

数学上可以表示为函数类型F:AB的包装器,其中A是参数类型,B是返回类型。

声明语法[编辑 | 编辑源代码]

基本声明格式:

#include <functional>

std::function<return_type(parameter_types)> func_name;

示例声明:

std::function<int(int, int)> binary_op;  // 包装返回int,接受两个int参数的函数
std::function<void()> callback;          // 包装无参数无返回的函数

基础用法示例[编辑 | 编辑源代码]

包装普通函数[编辑 | 编辑源代码]

#include <iostream>
#include <functional>

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

int main() {
    std::function<int(int, int)> func = add;
    std::cout << "Result: " << func(3, 4) << std::endl;  // 输出: Result: 7
    return 0;
}

包装Lambda表达式[编辑 | 编辑源代码]

#include <iostream>
#include <functional>

int main() {
    std::function<int(int)> square = [](int x) { return x * x; };
    std::cout << "Square of 5: " << square(5) << std::endl;  // 输出: Square of 5: 25
    return 0;
}

包装函数对象[编辑 | 编辑源代码]

#include <iostream>
#include <functional>

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

int main() {
    std::function<int(int, int)> func = Multiply();
    std::cout << "Product: " << func(3, 4) << std::endl;  // 输出: Product: 12
    return 0;
}

成员函数处理[编辑 | 编辑源代码]

包装成员函数需要结合std::bind或lambda表达式:

#include <iostream>
#include <functional>

class MyClass {
public:
    int memberFunc(int x) {
        return x * 2;
    }
};

int main() {
    MyClass obj;
    // 使用std::bind
    std::function<int(int)> func1 = std::bind(&MyClass::memberFunc, &obj, std::placeholders::_1);
    // 使用lambda
    std::function<int(int)> func2 = [&obj](int x) { return obj.memberFunc(x); };
    
    std::cout << func1(5) << ", " << func2(5) << std::endl;  // 输出: 10, 10
    return 0;
}

状态检查[编辑 | 编辑源代码]

使用operator bool()检查是否包含有效目标:

#include <iostream>
#include <functional>

void checkFunction(const std::function<void()>& func) {
    if (func) {
        std::cout << "Function is callable" << std::endl;
        func();
    } else {
        std::cout << "Function is empty" << std::endl;
    }
}

int main() {
    std::function<void()> emptyFunc;
    checkFunction(emptyFunc);  // 输出: Function is empty
    
    emptyFunc = []{ std::cout << "Hello!" << std::endl; };
    checkFunction(emptyFunc);  // 输出: Function is callable 然后输出: Hello!
    return 0;
}

性能考虑[编辑 | 编辑源代码]

std::function的实现通常使用类型擦除(Type Erasure)技术,这会带来一定的性能开销:

flowchart TD A[调用std::function] --> B[虚函数表查找] B --> C[动态分配内存] C --> D[实际函数调用]

与直接函数调用相比,std::function的调用大约有2-3倍的性能下降。在性能关键路径上应考虑直接使用模板或函数指针。

实际应用案例[编辑 | 编辑源代码]

回调机制[编辑 | 编辑源代码]

在事件驱动系统中广泛使用:

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

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

int main() {
    Button btn;
    btn.setOnClick([]() {
        std::cout << "Button clicked!" << std::endl;
    });
    btn.click();  // 输出: Button clicked!
    return 0;
}

策略模式实现[编辑 | 编辑源代码]

运行时替换算法策略:

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

class Sorter {
    std::function<void(std::vector<int>&)> strategy;
public:
    void setStrategy(const std::function<void(std::vector<int>&)>& s) {
        strategy = s;
    }
    void sort(std::vector<int>& data) {
        if (strategy) strategy(data);
    }
};

int main() {
    Sorter sorter;
    std::vector<int> data = {5, 2, 8, 1, 9};
    
    // 设置冒泡排序策略
    sorter.setStrategy([](std::vector<int>& v) {
        for (size_t i = 0; i < v.size(); ++i)
            for (size_t j = 0; j < v.size()-i-1; ++j)
                if (v[j] > v[j+1]) std::swap(v[j], v[j+1]);
    });
    sorter.sort(data);
    
    for (int n : data) std::cout << n << " ";  // 输出: 1 2 5 8 9
    return 0;
}

与函数指针比较[编辑 | 编辑源代码]

特性 std::function 函数指针
可调用类型 任何可调用对象 仅普通函数
捕获状态 可以 不可以
类型安全
性能 较低 较高
灵活性

常见问题[编辑 | 编辑源代码]

为什么使用std::function而不是auto?[编辑 | 编辑源代码]

  • auto在编译时确定类型,无法存储在容器中或作为类成员
  • std::function提供统一的类型接口,便于传递和存储

如何传递带捕获的lambda?[编辑 | 编辑源代码]

直接赋值即可,std::function会自动处理捕获状态:

int x = 10;
std::function<int()> func = [x]() { return x * 2; };

总结[编辑 | 编辑源代码]

std::function是C++中强大的函数包装器,它:

  • 提供统一的调用接口
  • 支持多种可调用对象
  • 实现类型安全的回调机制
  • 在需要运行时多态性的场景特别有用

页面模块:Message box/ambox.css没有内容。

扩展阅读[编辑 | 编辑源代码]

  • C++标准库文档:std::function
  • 类型擦除技术
  • 函数式编程概念