C++ std::function


std::function 是 C++11 引入的一个非常有用的模板类,它能够封装任何可以调用的目标(例如普通函数、函数指针、Lambda 表达式、成员函数或其他可调用对象),并使得它们可以像函数一样进行调用。它提供了一种灵活、统一的方式来处理各种类型的函数对象。

1. 基本概念

std::function 是一个可以存储任何符合指定签名的可调用对象的类型擦除封装器。它允许你通过统一的接口来调用不同类型的可调用对象,而无需关心其具体类型。

2. 语法

#include <functional>

std::function<返回类型(参数类型...)> 函数对象名;

3. 功能和用法

3.1. 普通函数指针

std::function 可以存储和调用普通的函数指针。

#include <iostream>
#include <functional>

void print_sum(int a, int b) {
    std::cout << "Sum: " << a + b << std::endl;
}

int main() {
    std::function<void(int, int)> func = print_sum;
    func(3, 5);  // 输出: Sum: 8
    return 0;
}

3.2. Lambda 表达式

std::function 也可以封装 lambda 表达式,lambda 表达式提供了一个非常灵活的方式来创建临时函数对象。

#include <iostream>
#include <functional>

int main() {
    std::function<int(int, int)> add = [](int a, int b) { return a + b; };
    std::cout << add(3, 4) << std::endl;  // 输出: 7
    return 0;
}

3.3. 函数对象

std::function 可以存储自定义的函数对象(即实现了 operator() 的类)。


#include <iostream>
#include <functional>

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

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

3.4. 成员函数指针

std::function 还支持封装成员函数,但需要注意它的使用方式。成员函数需要一个对象实例才能调用,所以你需要提供一个对象或者绑定到对象。


#include <iostream>
#include <functional>

class Printer {
public:
    void print_message(const std::string& message) {
        std::cout << message << std::endl;
    }
};

int main() {
    Printer printer;
    std::function<void(const std::string&)> print_func = 
        std::bind(&Printer::print_message, &printer, std::placeholders::_1);
    
    print_func("Hello, World!");  // 输出: Hello, World!
    return 0;
}

3.5. 参数和返回值

std::function 是类型安全的,可以根据你给定的签名来确定可调用对象的类型,它会检查传入的参数和返回值类型是否匹配。

4. 主要操作

4.1. std::function 的赋值和调用

你可以将函数指针、lambda 或者函数对象赋给 std::function 变量。
使用 () 运算符调用存储的函数。


std::function<void()> func = some_function;
func();  // 调用 some_function

4.2. std::function 的重置

你可以使用 std::function::reset() 重置 std::function 对象,使其不再指向任何可调用对象。


std::function<void()> func = some_function;
func();  // 调用 some_function
func.reset();  // 重置,不再指向任何函数

4.3. std::function 的空检查

可以使用 std::function::operator bool() 来检查 std::function 是否为空。

std::function<void()> func;
if (func) {
    func();  // 如果 func 非空则调用
} else {
    std::cout << "No function to call." << std::endl;
}

5. 性能注意事项

std::function 是类型擦除的,意味着它会对不同的可调用对象进行动态分配和类型擦除,所以它的性能可能比直接使用普通函数指针或 lambda 表达式要差一些。尤其是在频繁调用时,可能会造成一定的性能开销。

6. 适用场景

  • 回调函数:std::function 非常适合用于需要回调的场景,例如事件处理、异步编程等。
  • 函数式编程:通过将函数作为参数传递,std::function 可以让代码更具灵活性和可扩展性。
  • 事件驱动编程:可以用来处理事件驱动的框架,像 GUI 编程中按钮点击事件等。
  • 结合std::unordered_map:std::unordered_map<std::string, std::function<void(par)>> mapping.

7. 示例:使用 std::function 实现简单的回调

#include <iostream>
#include <functional>

void my_function(int a) {
    std::cout << "Callback called with: " << a << std::endl;
}

void invoke_callback(std::function<void(int)> callback) {
    // 触发回调
    callback(42);
}

int main() {
    std::function<void(int)> callback = my_function;
    invoke_callback(callback);  // 输出: Callback called with: 42
    return 0;
}

总结

std::function 是一个非常强大的工具,可以将不同类型的可调用对象统一封装并调用。它在需要高度灵活性的场景中非常有用,尤其是涉及回调和事件驱动的编程模式时。尽管它的性能可能略逊色于普通函数指针和直接的 Lambda 表达式,但它提供的高度抽象和灵活性使得它在许多高级用法中非常值得使用。

### C++ 中 `std::function` 的用法 `std::function` 是 C++ 标准库中的一个类模板,用于封装可调用对象(如函数指针、lambda 表达式、绑定表达式或其他可调用的对象)。这使得可以将任何类型的回调机制统一处理。 #### 基本定义与声明 为了使用 `std::function`,需要包含头文件 `<functional>`。下面是一个简单的例子来展示如何声明和初始化它: ```cpp #include <iostream> #include <functional> // 定义一个普通的函数作为示例 void greet(const std::string& name) { std::cout << "Hello, " << name << "!" << std::endl; } int main() { // 使用 std::function 来存储指向 void(std::string const&) 类型的函数 std::function<void(const std::string&)> func = greet; // 调用该函数 func("World"); return 0; } ``` 这段代码展示了怎样创建并赋值给 `std::function` 对象[^1]。 #### 存储 Lambda 表达式 除了普通函数外,还可以把 lambda 表达式存入到 `std::function` 中去: ```cpp #include <iostream> #include <functional> int main(){ // 创建一个带有捕获列表的 lambda 函数 int factor = 2; auto multiplyByFactor = [factor](int num){return num * factor;}; // 将其转换成 std::function std::function<int(int)> fnMultiply = multiplyByFactor; // 执行这个函数 std::cout << "Result is: " << fnMultiply(5) << '\n'; return 0; } ``` 这里说明了如何通过捕捉外部变量的方式构建更复杂的逻辑,并将其保存至 `std::function` 实例中。 #### 绑定成员函数 对于类的方法也可以利用 `std::bind()` 或者直接传递实例加方法名的方式来实现同样的效果: ```cpp #include <iostream> #include <memory> #include <functional> class MyClass { public: void say_hello(const std::string& message){ std::cout << "MyClass says:" << message << "\n"; } }; int main(){ auto obj_ptr = std::make_shared<MyClass>(); // 方法一:使用 bind() std::function<void(const std::string&)> bound_method_1 = std::bind(&MyClass::say_hello, obj_ptr, std::placeholders::_1); // 方法二:直接指定对象及其成员函数 std::function<void(const std::string&)> bound_method_2 = [&obj_ptr](const std::string& msg){ obj_ptr->say_hello(msg); }; // 测试两种方式的效果相同 bound_method_1("hello from method 1."); bound_method_2("hello from method 2."); return 0; } ``` 上述片段解释了当涉及到面向对象编程时,应该如何操作类内的非静态成员函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值