文章目录
C++从配置文件按序号调用函数
一、功能概述
本实现提供了一套从配置文件读取函数名,并按照配置文件中指定的序号顺序执行对应函数的机制。支持键值对格式的配置文件(序号=函数名
),程序会自动按序号升序解析并执行函数,无需依赖配置文件中的物理顺序。
二、配置文件格式说明
1. 格式定义
配置文件采用键值对格式,每行一个配置项,格式为:
序号=函数名
- 序号:非负整数(如1、2、3),用于指定函数执行顺序
- 函数名:需与程序中已注册的函数名完全匹配
当然,也可以根据自己需求自己定义规则
2. 示例(config.txt)
3=func3
1=func1
2=func2
说明:即使配置文件中函数顺序混乱,程序仍会按序号1→2→3的顺序执行
三、代码实现
1. 核心文件结构
项目目录/
├── main.cpp // 主程序逻辑
└── config.txt // 配置文件
2. 完整代码(main.cpp)
#include <iostream>
#include <fstream>
#include <string>
#include <unordered_map>
#include <functional>
#include <sstream>
#include <vector>
#include <algorithm>
// 定义函数类型(无参数无返回值示例,可根据需求扩展)
using Function = std::function<void()>;
// 示例函数实现
void func1() {
std::cout << "执行函数1" << std::endl;
}
void func2() {
std::cout << "执行函数2" << std::endl;
}
void func3() {
std::cout << "执行函数3" << std::endl;
}
// 解析配置文件:读取序号-函数名映射
bool parseConfig(const std::string& filename, std::vector<std::pair<int, std::string>>& config) {
std::ifstream file(filename);
if (!file.is_open()) {
std::cerr << "错误:无法打开配置文件 " << filename << std::endl;
return false;
}
std::string line;
while (std::getline(file, line)) {
// 跳过空行
if (line.empty()) continue;
// 分割键值对(格式:序号=函数名)
size_t eqPos = line.find('=');
if (eqPos == std::string::npos) {
std::cerr << "警告:无效配置行 - " << line << "(跳过)" << std::endl;
continue;
}
// 解析序号和函数名
std::string keyStr = line.substr(0, eqPos);
std::string funcName = line.substr(eqPos + 1);
try {
int key = std::stoi(keyStr);
config.emplace_back(key, funcName);
} catch (const std::exception& e) {
std::cerr << "警告:无效序号 " << keyStr << "(跳过)" << std::endl;
}
}
file.close();
return true;
}
int main() {
// 1. 注册函数:建立函数名到函数的映射
std::unordered_map<std::string, Function> funcMap = {
{"func1", func1},
{"func2", func2},
{"func3", func3}
};
// 2. 解析配置文件
std::vector<std::pair<int, std::string>> config;
if (!parseConfig("config.txt", config)) {
return 1; // 解析失败则退出
}
// 3. 按序号升序排序
std::sort(config.begin(), config.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
// 4. 按顺序执行函数
std::cout << "开始按序号执行函数..." << std::endl;
for (const auto& [key, funcName] : config) {
auto it = funcMap.find(funcName);
if (it != funcMap.end()) {
std::cout << "执行序号 " << key << ":";
it->second(); // 调用函数
} else {
std::cerr << "警告:函数 " << funcName << "(序号 " << key << ")未注册(跳过)" << std::endl;
}
}
return 0;
}
四、核心实现逻辑
-
函数注册机制
通过std::unordered_map
建立函数名与函数指针的映射(funcMap
),确保配置文件中的函数名能找到对应的可执行函数。 -
配置文件解析
- 逐行读取配置文件,分割
序号=函数名
格式的字符串 - 过滤无效行(空行、无
=
符号的行、序号非整数的行) - 存储为
(序号, 函数名)
的键值对列表
- 逐行读取配置文件,分割
-
排序与执行
- 使用
std::sort
按序号升序排列配置项 - 遍历排序后的列表,通过函数名在
funcMap
中查找并执行函数
- 使用
五、扩展与注意事项
1. 扩展方向
- 支持带参数的函数:修改
Function
类型为std::function<void(参数类型...)>
,并在配置文件中添加参数解析(如1=func1(10, "test")
) - 支持更多配置格式:集成JSON/YAML解析库(如nlohmann/json),处理更复杂的配置
- 动态加载函数:结合
dlopen
(Linux)或LoadLibrary
(Windows)实现动态库中的函数调用
2. 注意事项
- 配置文件中的函数名必须与
funcMap
中注册的名称完全一致(区分大小写) - 序号需为整数,重复序号会按最后出现的函数名执行(可根据需求添加去重逻辑)
- 生产环境中建议增加文件权限检查、配置项数量限制等安全机制
六、运行示例
输入(config.txt)
3=func3
1=func1
2=func2
输出
开始按序号执行函数...
执行序号 1:执行函数1
执行序号 2:执行函数2
执行序号 3:执行函数3
也可以随便配置调用函数