如何在C++17中定义递归的std::variant类型Value?
在C++17中实现递归std::variant类型Value
你的原始定义无法通过编译,因为C++17要求std::variant的模板参数必须是完整类型——当你定义Value时,std::vector<std::pair<std::string, Value>>中的Value还未完成定义,属于不完全类型,因此编译器会报错。
在C++17中,你需要通过间接持有的方式实现递归类型,以下是两种可行方案:
方案一:用std::unique_ptr包装递归集合类型
这种方式通过动态分配的指针绕开不完全类型的限制,是最直接的实现方式:
#include <variant> #include <vector> #include <string> #include <memory> using Value = std::variant< bool, int, float, std::unique_ptr<std::vector<std::pair<std::string, Value>>> >;
使用示例
// 创建一个包含键值对的集合 auto obj = std::make_unique<std::vector<std::pair<std::string, Value>>>(); obj->emplace_back("age", 30); obj->emplace_back("is_employed", true); obj->emplace_back("salary", 8500.5f); // 将集合存入Value Value data = std::move(obj); // 访问集合中的元素 if (auto* p_obj = std::get_if<std::unique_ptr<std::vector<std::pair<std::string, Value>>>>(&data)) { for (const auto& [key, val] : **p_obj) { // 根据val的类型做对应处理 std::visit([](const auto& v) { using T = std::decay_t<decltype(v)>; if constexpr (std::is_same_v<T, bool>) { // 处理bool类型 } else if constexpr (std::is_same_v<T, int>) { // 处理int类型 } else if constexpr (std::is_same_v<T, float>) { // 处理float类型 } else if constexpr (std::is_same_v<T, std::unique_ptr<std::vector<std::pair<std::string, Value>>>>) { // 处理嵌套的集合类型 } }, val); } }
方案二:用自定义结构体包装集合(语义更清晰)
如果你希望代码语义更明确,可以定义一个专门的结构体来存储键值对集合,再用指针包装:
#include <variant> #include <vector> #include <string> #include <memory> // 前置声明Value class Value; // 定义存储键值对的结构体 struct Object { std::vector<std::pair<std::string, Value>> items; }; // 完成Value的定义 using Value = std::variant< bool, int, float, std::unique_ptr<Object> >;
使用示例
访问时通过Object::items操作集合,逻辑与方案一类似:
auto obj = std::make_unique<Object>(); obj->items.emplace_back("height", 175); obj->items.emplace_back("is_student", false); obj->items.emplace_back("weight", 68.2f); Value data = std::move(obj); if (auto* p_obj = std::get_if<std::unique_ptr<Object>>(&data)) { for (const auto& [key, val] : (*p_obj)->items) { // 处理每个键值对 } }
额外说明
如果可以升级到C++20,则可以直接使用你最初的写法——C++20放宽了std::variant的模板参数限制,允许包含不完全类型,代码如下:
#include <variant> #include <vector> #include <string> using Value = std::variant< bool, int, float, std::vector<std::pair<std::string, Value>> >;
内容的提问来源于stack exchange,提问作者Stuart
相关产品推荐
相关产品推荐

