如何定义可存储不同签名lambda表达式的std::map?
如何在std::map中存储不同签名的Lambda表达式
当然有办法实现这个需求!既然你已经明确知道每个键对应的Lambda签名,我们可以借助C17提供的类型工具来统一map的value类型,同时兼容不同签名的函数。下面是两个在VS2017/C17环境下可正常编译的方案:
方案一:使用std::variant(类型安全首选)
std::variant是C++17引入的类型变体,它可以存储指定类型集合中的任意一种类型。我们可以把所有需要支持的std::function类型都放进variant里,作为map的value类型。
代码示例
#include <map> #include <functional> #include <variant> #include <string> // 定义包含所有需要的函数签名的variant类型 using FuncVariant = std::variant< std::function<bool(double)>, std::function<bool(double, double)> >; int main() { std::map<std::string, FuncVariant> func_map; // 插入不同签名的Lambda(自动匹配variant中的对应类型) func_map.emplace("gt_zero", [](double a) { return a > 0; }); func_map.emplace("lt_zero", [](double a) { return a < 0; }); func_map.emplace("equal", [](double a, double b) { return a == b; }); // 调用时,根据已知的签名用std::get获取对应的函数 bool foo = std::get<std::function<bool(double)>>(func_map["gt_zero"])(42); // 返回true bool bar = std::get<std::function<bool(double)>>(func_map["lt_zero"])(42); // 返回false bool baz = std::get<std::function<bool(double, double)>>(func_map["equal"])(42, 42); // 返回true // 安全调用方式(避免类型不匹配抛出异常) if (auto* gt_func = std::get_if<std::function<bool(double)>>(&func_map["gt_zero"])) { bool safe_foo = (*gt_func)(42); } return 0; }
这个方案的优势是类型安全,编译期就能检查部分类型错误,而且调用时的语义清晰。
方案二:使用std::any(更灵活)
std::any是C++17引入的通用类型擦除容器,可以存储任意类型的对象。它比variant更灵活,但类型安全稍弱,需要你确保调用时的类型转换正确。
代码示例
#include <map> #include <functional> #include <any> #include <string> int main() { std::map<std::string, std::any> func_map; // 插入时显式转换为对应std::function类型(避免Lambda匿名类型导致的转换问题) func_map.emplace("gt_zero", std::function<bool(double)>([](double a) { return a > 0; })); func_map.emplace("equal", std::function<bool(double, double)>([](double a, double b) { return a == b; })); // 调用时用std::any_cast转换为对应的函数类型 bool foo = std::any_cast<std::function<bool(double)>>(func_map["gt_zero"])(42); bool baz = std::any_cast<std::function<bool(double, double)>>(func_map["equal"])(42, 42); // 安全调用方式 if (auto* eq_func = std::any_cast<std::function<bool(double, double)>>(&func_map["equal"])) { bool safe_baz = (*eq_func)(42, 42); } return 0; }
注意事项
- 两个方案都需要在VS2017中开启C17编译选项(项目属性 -> C/C -> 语言 -> C++语言标准选择
ISO C++17标准(/std:c++17))。 - 因为你已知每个键对应的签名,所以调用时一定要使用匹配的类型进行转换,否则会抛出
std::bad_variant_access或std::bad_any_cast异常,建议使用std::get_if或std::any_cast的指针版本做安全检查。
内容的提问来源于stack exchange,提问作者buttonsrtoys
相关产品推荐
相关产品推荐

