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; // 输出 5

2. Lambda 表达式

std::function<int(int, int)> func = [](int a, int b) {
return a + b;
};
std::cout << func(2, 3) << std::endl; // 输出 5

3. 函数对象

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; // 输出 5

4. 成员函数

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; // 输出 6

3. 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 是一个纯虚类,包含 invokeclone 两个虚函数。不同的函数对象(如普通函数、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 提供了帮助。


已发布

分类

来自

标签:

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注