如何在循环中避免Lambda捕获,生成可存储的函数指针集合?
问题描述
想要存储一组Lambda生成的函数指针,这些函数的函数体高度相似,手动编写重复繁琐且难维护。原本想用Lambda捕获,但带捕获的Lambda无法转换为函数指针,且不想使用std::function这类较重的工具。以下是无法运行的示例代码:
#include <vector> int main() { std::vector<double(*)(int)> functions; for (int i = 0; i < 5; ++i) { functions.push_back([i](int v) -> double { return i * v; }); } }
解决方案
方法1:模板生成独立函数实例(编译期常量场景)
如果要捕获的值是编译期已知的常量,可以用模板参数传递这个值,每个模板实例会生成独立的函数,天然可转换为函数指针,完全无额外开销:
#include <vector> #include <cstdio> // 模板函数,用模板参数替代Lambda的捕获值 template<int Multiplier> double multiply(int v) { return Multiplier * v; } int main() { std::vector<double(*)(int)> functions; // 直接添加不同模板实例的函数指针 functions.push_back(&multiply<0>); functions.push_back(&multiply<1>); functions.push_back(&multiply<2>); functions.push_back(&multiply<3>); functions.push_back(&multiply<4>); // 测试调用 for (auto func : functions) { printf("%f\n", func(2)); // 输出:0.000000、2.000000、4.000000、6.000000、8.000000 } }
如果数量较多,C++17及以上可以用编译期循环(比如std::make_index_sequence)自动生成,避免手动重复添加。
方法2:静态上下文存储(单线程运行时场景)
如果捕获的值是运行时生成的,且处于单线程环境,可以用静态变量存储上下文,配合通用函数实现类似捕获的效果。注意需要额外存储每个函数对应的上下文值:
#include <vector> #include <cstdio> #include <utility> // 静态变量存储当前上下文(单线程安全) static int current_multiplier; // 通用函数,使用静态变量作为"捕获"值 double multiply_with_ctx(int v) { return current_multiplier * v; } int main() { // 存储函数指针+对应的上下文值 std::vector<std::pair<double(*)(int), int>> func_with_ctx; for (int i = 0; i < 5; ++i) { func_with_ctx.emplace_back(&multiply_with_ctx, i); } // 调用前先设置对应上下文 for (auto& [func, ctx] : func_with_ctx) { current_multiplier = ctx; printf("%f\n", func(2)); // 输出同方法1 } }
多线程场景下需要加锁,或者用线程局部存储(thread_local)替代静态变量。
方法3:修改函数签名传递上下文(最通用场景)
如果可以接受修改函数指针的签名,直接把原本要捕获的值作为参数传递,这是最简单、无任何额外开销的方案:
#include <vector> #include <cstdio> // 直接把乘数作为参数传入 double multiply(int v, int multiplier) { return multiplier * v; } int main() { std::vector<double(*)(int, int)> functions; // 所有元素都是同一个函数指针,因为逻辑完全一致 functions.resize(5, &multiply); // 调用时传入对应的乘数 for (int i = 0; i < functions.size(); ++i) { printf("%f\n", functions[i](2, i)); // 输出同方法1 } }
内容的提问来源于stack exchange,提问作者Joel
相关产品推荐
相关产品推荐

