如何通过函数返回std::map<int, std::variant>中对应键的值?
问题描述
我希望用std::map存储不同类型的值,定义了这样的容器:
std::map<int, std::variant<int, std::string>> m ={{1,1},{2,"asd"}};
现在想设计一个函数,通过键获取对应的值,函数形式如下:
auto get(int key) { ... return value; }
预期效果:
get(1) -> 1 get(2) -> "asd"
请问这是否可行?若可行,具体实现方案是什么?
补充说明:
该设计用于存储从配置文件读取的配置数据,读取后需要进行类型转换或数据变换。例如配置文件内容如下:
a=1 b=asd
读取后需处理为:m["a"]=int(3)(对应配置a=1,读取后数值加2)m["b"]=std::string("asdasd")(对应配置b=asd,读取后字符串翻倍)
因此我认为若有一个接口函数通过键获取准确值会更便捷。
可行方案实现
这完全可行,核心是利用std::variant的访问机制,结合C++的类型推导和模板特性实现。以下是几种适配不同场景的实现方式:
方式一:返回std::variant,由调用方处理类型
这是最直接的实现,返回值保留std::variant类型,让调用方根据需求处理不同类型:
#include <map> #include <variant> #include <string> #include <stdexcept> std::map<int, std::variant<int, std::string>> m = {{1, 1}, {2, "asd"}}; std::variant<int, std::string> get(int key) { auto it = m.find(key); if (it != m.end()) { return it->second; } // 键不存在时抛出异常,也可返回默认构造的variant throw std::out_of_range("Key not found in config map"); }
调用时用std::visit分支处理类型:
int main() { auto val = get(1); std::visit([](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, int>) { // 处理整数类型逻辑 } else if constexpr (std::is_same_v<T, std::string>) { // 处理字符串类型逻辑 } }, val); }
方式二:模板函数,指定返回类型
如果调用方明确知道目标值的类型,可以实现模板函数,强制获取指定类型的值:
#include <map> #include <variant> #include <string> #include <stdexcept> std::map<int, std::variant<int, std::string>> m = {{1, 1}, {2, "asd"}}; template<typename T> T get(int key) { auto it = m.find(key); if (it == m.end()) { throw std::out_of_range("Key not found"); } // 尝试获取指定类型,失败则抛出bad_variant_access异常 if (auto* ptr = std::get_if<T>(&it->second)) { return *ptr; } throw std::bad_variant_access(); }
调用示例:
int main() { int num = get<int>(1); // 得到int类型的1 std::string str = get<std::string>(2); // 得到std::string类型的"asd" }
方式三:自动推导返回类型(C++17及以上)
针对配置项类型固定的场景(每个键对应唯一类型),可以让函数自动推导返回类型,无需调用方显式指定:
#include <map> #include <variant> #include <string> #include <stdexcept> std::map<int, std::variant<int, std::string>> m = {{1, 1}, {2, "asd"}}; auto get(int key) { auto it = m.find(key); if (it == m.end()) { throw std::out_of_range("Key not found"); } // 通过std::visit转发原始值,编译器自动推导返回类型 return std::visit([](auto&& arg) -> decltype(auto) { return std::forward<decltype(arg)>(arg); }, it->second); }
调用时编译器会自动匹配返回类型:
int main() { auto num = get(1); // num类型为int auto str = get(2); // str类型为std::string }
这种方式仅适用于键与类型一一对应的场景,完全匹配你读取配置文件的需求。
内容的提问来源于stack exchange,提问作者f1msch
相关产品推荐
相关产品推荐

