C++11新特性:std::function详解
std::function 是 C++11 引入的一个非常强大的标准库工具,专门用于存储和调用任意类型的可调用对象(如函数、Lambda 表达式、函数对象等)。本文将带你深入了解 std::function 的用途、实现原理及其在实际开发中的应用。
1. 什么是 std::function
std::function 是一个模板类,用于封装任意可调用对象,使其可以以统一的方式进行存储和调用。它主要用于需要传递、存储或返回函数对象的场合。
例如,下面的代码展示了如何将普通函数和 Lambda 表达式赋值给 std::function:
std::function<int(int, int)> func = add;func = [](int a, int b) { return a + b; };2. std::function 的基本用法
1. 普通函数
int add(int a, int b) { return a + b;}std::function<int(int, int)> func = add;std::cout << func(2, 3) << std::endl; // 输出 52. Lambda 表达式
std::function<int(int, int)> func = [](int a, int b) { return a + b;};std::cout << func(2, 3) << std::endl; // 输出 53. 函数对象
struct Adder { int operator()(int a, int b) const { return a + b; }};std::function<int(int, int)> func = Adder();std::cout << func(2, 3) << std::endl; // 输出 54. 成员函数
struct Calculator { int multiply(int a, int b) const { return a * b; }};Calculator calc;std::function<int(int, int)> func = std::bind(&Calculator::multiply, calc, std::placeholders::_1, std::placeholders::_2);std::cout << func(2, 3) << std::endl; // 输出 63. std::function 的内部实现
#include <iostream>#include <memory>#include <utility>
template <typename>class function; // Forward declaration
template <typename R, typename... Args>class function<R(Args...)> {public: function() noexcept : callable(nullptr) {}
template <typename F> function(F f) : callable(new CallableType<F>(std::move(f))) {}
function(const function& other) : callable(other.callable ? other.callable->clone() : nullptr) {}
function(function&& other) noexcept : callable(std::move(other.callable)) { other.callable = nullptr; }
function& operator=(const function& other) { if (this != &other) { callable.reset(other.callable ? other.callable->clone() : nullptr); } return *this; }
function& operator=(function&& other) noexcept { if (this != &other) { callable = std::move(other.callable); other.callable = nullptr; } return *this; }
R operator()(Args... args) const { if (!callable) { throw std::bad_function_call(); } return callable->invoke(std::forward<Args>(args)...); }
explicit operator bool() const noexcept { return callable != nullptr; }
private: struct CallableBase { virtual ~CallableBase() = default; virtual R invoke(Args... args) const = 0; virtual CallableBase* clone() const = 0; };
template <typename F> struct CallableType : CallableBase { F f;
explicit CallableType(F&& func) : f(std::forward<F>(func)) {}
R invoke(Args... args) const override { return f(std::forward<Args>(args)...); }
CallableBase* clone() const override { return new CallableType(f); } };
std::unique_ptr<CallableBase> callable;};1. 模板参数详解
std::function 的模板参数是一个函数类型,例如 std::function<int(int, int)>。其中 int(int, int) 是函数类型,int 是返回类型,(int, int) 是参数列表。这种形式允许 std::function 存储任何与该签名匹配的可调用对象。
2. 内部的多态与深拷贝
在 std::function 的实现中,使用了一个名为 CallableBase 的抽象基类,用于定义一个通用的接口,存储和调用被封装的函数对象。CallableBase 是一个纯虚类,包含 invoke 和 clone 两个虚函数。不同的函数对象(如普通函数、Lambda 等)会派生出具体的类,实现这些虚函数以实现多态。
struct CallableBase { virtual ~CallableBase() {} virtual R invoke(Args... args) = 0; virtual CallableBase* clone() const = 0;};4. 主要使用场景及示例
1. 回调函数
回调函数是在异步操作完成后调用的函数,通常用于通知操作的结果或状态。std::function 允许将任意类型的回调函数传递给异步操作:
void asyncOperation(const std::function<void(int)>& callback) { // 模拟异步操作 callback(42);}2. 多态性
std::function 可以存储和调用不同类型的可调用对象,这使得在需要多态行为的场景下非常有用:
void callFunction(const std::function<void()>& func) { func(); // 调用传递进来的任意可调用对象}3. 函数对象的存储与传递
你可以使用 std::function 来存储和传递多个函数对象,然后在需要时调用它们:
std::vector<std::function<void(int)>> funcs;funcs.push_back([](int x) { std::cout << "Lambda called with: " << x << std::endl; });5. 高级应用:事件处理系统与不定长参数
在某些情况下,事件处理系统需要处理不定长参数。通过结合 std::function 和模板参数包 Args...,可以实现更加灵活的事件处理机制:
#include <iostream>#include <functional>#include <map>#include <string>class EventSystem {public: // 使用模板和参数包注册事件处理函数 template<typename... Args> void registerEvent(const std::string& eventName, std::function<void(Args...)> handler) { handlers[eventName] = [handler](std::vector<std::any> args) { // 将 std::any 转换回原始类型并调用处理函数 invokeHandler<Args...>(handler, args, std::index_sequence_for<Args...>{}); }; } // 使用模板和参数包触发事件 template<typename... Args> void triggerEvent(const std::string& eventName, Args... args) { auto it = handlers.find(eventName); if (it != handlers.end()) { // 将参数打包为 std::vector<std::any> 传递给通用调用器 it->second({std::any(args)...}); } }private: // 存储通用事件处理函数(使用 std::any 作为参数类型) std::map<std::string, std::function<void(std::vector<std::any>)>> handlers; // 帮助函数:将 std::any 转换为原始类型并调用处理函数 template<typename... Args, std::size_t... I> static void invokeHandler(std::function<void(Args...)> handler, const std::vector<std::any>& args, std::index_sequence<I...>) { handler(std::any_cast<Args>(args[I])...); }};示例
完整示例展示了如何使用 std::function 实现带有不定长参数的事件处理系统:
int main() { EventSystem es; // 注册带参数的事件处理函数 es.registerEvent<int, int>("onAdd", [](int a, int b) { std::cout << "Sum: " << a + b << std::endl; }); // 触发事件并传递参数 es.triggerEvent("onAdd", 3, 5); return 0;}6. 总结与反思
std::function 是 C++11 中一个非常重要的新特性,它大大增强了 C++ 处理函数对象的灵活性。无论是简单的回调函数,还是复杂的事件系统,std::function 都提供了强大的支持。通过对其内部实现的理解,可以更好地利用它来编写高效、灵活的代码。希望本教程对你深入理解 std::function 提供了帮助。