返回顶部
分享到

C++中std::functional使用场景

C语言 来源:互联网 作者:佚名 发布时间:2026-02-23 08:09:01 人浏览
摘要

std::functional 是 C++ 标准库中一个非常强大的工具,它提供了一种**类型擦除(type erasure)**机制,让你能够存储、传递和调用任何可调用对象(callable)。 核心作用 1.统一的可调用对象包装器

std::functional 是 C++ 标准库中一个非常强大的工具,它提供了一种**类型擦除(type erasure)**机制,让你能够存储、传递和调用任何可调用对象(callable)。

核心作用

1.统一的可调用对象包装器

std::function 可以包装任何可调用实体,只要签名匹配:

  • 普通函数
  • Lambda 表达式
  • 函数对象(仿函数)
  • 成员函数(通过 std::bind 或 lambda)
  • 甚至其他 std::function

2.类型擦除

隐藏具体类型,只暴露接口。这使得你可以:

  • 在容器中存储不同类型的可调用对象
  • 作为函数参数接受任意可调用对象
  • 实现回调机制而不需要模板

主要使用场景

场景 1:回调函数(Callbacks)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include <functional>

#include <iostream>

 

class Button {

    std::function<void()> onClick_;

public:

    void setOnClick(std::function<void()> callback) {

        onClick_ = callback;

    }

    void click() { if (onClick_) onClick_(); }

};

 

// 使用

Button btn;

btn.setOnClick([]() { std::cout << "Clicked!\n"; });

btn.click();

场景 2:策略模式 / 算法注入

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#include <functional>

#include <vector>

#include <algorithm>

 

void processData(std::vector<int>& data,

                 std::function<bool(int)> filter,

                 std::function<int(int)> transform) {

    // 先过滤

    data.erase(std::remove_if(data.begin(), data.end(),

              [&](int x) { return !filter(x); }), data.end());

    // 再转换

    for (auto& x : data) x = transform(x);

}

 

// 使用

std::vector<int> nums = {1, 2, 3, 4, 5, 6};

processData(nums,

    [](int x) { return x % 2 == 0; },  // 只保留偶数

    [](int x) { return x * x; }         // 平方

);

场景 3:事件系统 / 观察者模式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

#include <functional>

#include <vector>

#include <string>

 

class EventSystem {

    std::vector<std::function<void(const std::string&)>> listeners_;

public:

    void subscribe(std::function<void(const std::string&)> listener) {

        listeners_.push_back(listener);

    }

    void emit(const std::string& event) {

        for (auto& listener : listeners_) {

            listener(event);

        }

    }

};

 

// 使用

EventSystem events;

events.subscribe([](const std::string& e) {

    std::cout << "Logger: " << e << "\n";

});

events.subscribe([](const std::string& e) {

    std::cout << "Metrics: recorded " << e << "\n";

});

场景 4:延迟执行 / 任务队列

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

#include <functional>

#include <queue>

#include <iostream>

 

class TaskQueue {

    std::queue<std::function<void()>> tasks_;

public:

    void addTask(std::function<void()> task) {

        tasks_.push(task);

    }

    void runAll() {

        while (!tasks_.empty()) {

            tasks_.front()();

            tasks_.pop();

        }

    }

};

 

// 使用

TaskQueue queue;

queue.addTask([]() { std::cout << "Task 1\n"; });

queue.addTask([]() { std::cout << "Task 2\n"; });

queue.runAll();

场景 5:绑定成员函数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include <functional>

#include <iostream>

 

class Calculator {

public:

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

    int multiply(int a, int b) { return a * b; }

};

 

// 使用 std::bind

Calculator calc;

auto addFunc = std::bind(&Calculator::add, &calc,

                         std::placeholders::_1, std::placeholders::_2);

std::cout << addFunc(3, 4); // 7

 

// 或者使用 lambda(更推荐,性能更好)

auto multiplyFunc = [&calc](int a, int b) {

    return calc.multiply(a, b);

};

std::functionvs 模板 vs 裸函数指针

特性 std::function 模板 裸函数指针
类型擦除 ? 是 ? 否 ? 是(但只能指向函数)
存储 Lambda ? 可以 ? 可以 ? 不行(除非无捕获)
运行时开销 有(虚函数调用)
编译时类型检查 弱(运行时可能抛 bad_function_call)
存储在容器中 ? 容易 ? 难(需要类型擦除) ? 可以

最佳实践

  1. 优先使用模板:如果不需要存储可调用对象,用模板参数更高效

    1

    2

    3

    4

    5

    6

    // 更好:零开销

    template<typename Func>

    void execute(Func&& f) { f(); }

     

    // 有开销:类型擦除

    void execute(std::function<void()> f) { f(); }

  2. 检查空状态:调用前确保 std::function 不为空

    1

    if (func) func();  // 或 if (func != nullptr)

  3. 注意开销:std::function 通常使用小对象优化(SOO),但大对象会堆分配

  4. C++23 替代:考虑使用 std::move_only_function(仅移动)或 std::copyable_function

std::functional 的核心价值在于灵活性——当你需要在运行时决定调用什么、或者需要在容器中存储可调用对象时,它是不可或缺的工具。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。

您可能感兴趣的文章 :

原文链接 :
相关文章
  • C++中的引用传参和指针传参的区别介绍
    核心概念对比 概念 C++ 前端 (JS/TS) 值传递 默认方式,完整拷贝 基本类型 (number, string等) 引用传递 需显式使用 或指针 对象、数组、函数等引
  • C++中std::functional使用场景
    std::functional 是 C++ 标准库中一个非常强大的工具,它提供了一种**类型擦除(type erasure)**机制,让你能够存储、传递和调用任何可调用对象
  • C++入门指南:零基础入门教学
    学习C++就像学习一门新的语言,需要从字母开始,逐步构建句子和段落。本文就是你的C++字母表。本文介绍了C++编程语言的基本概念和学习
  • C++ io_uring的使用
    io_uring是 Linux 内核在 5.1 版本引入的一套全新的、高性能的异步 I/O (Asynchronous I/O) 接口。它的出现是为了解决旧有的epoll和linux-aio在面对现代
  • C++特有的bool变量使用
    C++中的bool类型 在C++中,bool是一种基本数据类型,专门用于表示布尔值(真或假)。它是C++语言特有的布尔类型,与C语言中使用整数模拟布
  • C++右值引用(rvalue references)与移动语义(move semant
    一、右值引用(rvalue references)与移动语义(move semantics)设计动机 1.1 为什么需要移动语义 传统 C++ 的对象拷贝(copy)在管理资源(堆内存
  • c++日志库log4cplus快速入门

    c++日志库log4cplus快速入门
    log4j 用于Java,log4cplus从它衍生而来,用于c++。 用于c++的日志库还有很多,如 log4cxx等,可以根据实际需求选择使用。 log4cplus 的地址:http
  • 从入门到精通C++11 <chrono> 库特性

    从入门到精通C++11 <chrono> 库特性
    在 C++11 标准中,引入了许多新的库特性,其中chrono库为时间处理提供了强大而灵活的支持。这个库使得在 C++ 中处理时间变得更加方便和精
  • C++ Sort函数使用场景分析

    C++ Sort函数使用场景分析
    C++ Sort函数详解 前言 :sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某
  • 使用DeepSeek API 结合VSCode提升开发效率

    使用DeepSeek API 结合VSCode提升开发效率
    在当今的软件开发领域,API 的使用已经成为不可或缺的一部分。DeepSeek 是一个强大的 API 平台,提供了丰富的功能和数据,可以帮助开发者
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计