C语言
主页 > 软件编程 > C语言 >

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

2026-02-23 | 佚名 | 点击:

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

核心作用

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

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 的核心价值在于灵活性——当你需要在运行时决定调用什么、或者需要在容器中存储可调用对象时,它是不可或缺的工具。

原文链接:
相关文章
最新更新