【编程技巧】C++如何使用std::map管理std::function函数指针
一、问题背景
开发过程中遇到了需要根据const字符串调用不同函数的要求。在开发过程中为了快速实现功能,实际使用了if else等判断实现了不同函数的调用,徒增了不少代码行数。
明知道可以采用map管理函数指针,但是没有具体实现过,所以不敢贸然采用。为避免凑代码行数之嫌,决定使用这种方式去更新写法,现将学习过程记录下来。
二、std::map管理函数指针
使用 std::map
(或其他关联容器,如 std::unordered_map
)来管理 function
函数指针,可以为程序设计带来许多优势,尤其在需要动态管理和调用函数的场景中。具体包括以下优点:
- 动态映射与查找:使用
std::map
可以将特定的标识符(如std::string
、int
等)与函数指针或std::function
关联起来,使得程序能够根据需求在运行时动态查找并调用函数,而无需编写复杂的switch-case
或if-else
语句。 - 简化代码结构,易于扩展:当有新的功能需要添加时,只需向
std::map
中插入新的函数指针即可,而不必更改原有的代码逻辑。这样可以极大地提高代码的可维护性和扩展性。如果将来需要替换或修改某个功能,只需更新映射中的函数指针即可。 - 高效查询与调用:
std::map
和std::unordered_map
提供了高效的查找功能。std::map
是一个基于红黑树实现的有序容器,查找时间复杂度为 O(log n),而std::unordered_map
是基于哈希表实现的无序容器,查找时间复杂度为平均 O(1)。使用这些容器管理函数指针,程序可以快速找到并执行目标函数。
三、std::function
(1)std::function定义
类模板std::function
是 C++ 标准库中的一个通用多态函数包装器,位于 <functional>
头文件中。它可以用来存储、复制和调用任何符合特定函数签名的可调用对象,比如普通函数、lambda 表达式、std::bind
生成的函数对象,或者是函数对象类的实例。
存储的可调用对象称为std::function
的目标。如果std::function
不包含目标,则称为空函数。调用空的std::function
的目标函数会产生std::bad_function_call
异常。
(2)std::function语法
#include <functional>
std::function<ReturnType(ArgTypes...)>
ReturnType:指定函数的返回类型。
ArgTypes…:指定函数的参数类型列表。
(3)std::function 与传统函数指针的区别
std::function 是 C++11 引入的一个模板类,它可以存储、复制和调用任何可调用对象,包括函数指针、lambda 表达式、函数对象等。而传统函数指针则只能指向函数。
相较于传统函数指针,std::function具有更强的类型安全性,但性能上略低于传统函数指针。
四、具体实现
实现步骤如下:
- 采用别名
FunctionPtr
代替std::function<void(int, int)>
。 - 定义具名函数
void func1(int, int)
和void func2(int, int)
,分别实现加法和乘法。 - 定义匿名函数
void(int, int)
实现减法。 - 定义
std::map<std::string, std::shared_ptr<FunctionPtr>> functionMap;
用于管理上述函数。 - 此时
functionMap
能够根据传入的string不同调用不同的函数。
#include <iostream>
#include <map>
#include <memory>
#include <functional>using FunctionPtr = std::function<void(int, int)>;void func1(int x, int y) {std::cout << "In func1, x + y = " << x + y << std::endl;
}void func2(int x, int y) {std::cout << "In func2, x * y = " << x * y << std::endl;
}int main() {std::map<std::string, std::shared_ptr<FunctionPtr>> functionMap;functionMap["func1"] = std::make_shared<FunctionPtr>(func1);functionMap["func2"] = std::make_shared<FunctionPtr>(func2);functionMap["func3"] = std::make_shared<FunctionPtr>([](int x, int y) -> void {std::cout << "In func3, x - y = " << x - y << std::endl;});for (const auto &functionPair : functionMap) {auto funcName = functionPair.first;std::cout << "In main, funcName = " << funcName << std::endl;auto function = functionPair.second;if (function != nullptr) {(*function)(1,2);}}return 0;
}
五、参考文献
- Cpp Reference之std::map:https://en.cppreference.com/w/cpp/container/map。
- Cpp Reference之std::function:https://en.cppreference.com/w/cpp/utility/functional/function