You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用boost::pfr::for_each_field_with_name实现哈希表转嵌套结构体?

实现方案:从std::unordered_map<std::string, double>还原嵌套结构体

基于你已用boost::pfr::for_each_field_with_name实现的序列化逻辑,逆向的from_hashmap可以利用同样的反射能力,通过路径解析+递归遍历结构体字段完成还原。核心思路是将哈希表中带层级的键(比如"addr.lat")拆分为字段路径,逐层定位到结构体中的目标字段并赋值。

步骤1:路径拆分辅助函数

首先需要把哈希表的键(嵌套路径字符串)拆分为层级字段名列表,比如把"person.addr.lng"拆成{"person", "addr", "lng"}:

#include <vector>
#include <string>
#include <sstream>

std::vector<std::string> split_path(const std::string& path) {
    std::vector<std::string> parts;
    std::stringstream ss(path);
    std::string part;
    while (std::getline(ss, part, '.')) {
        if (!part.empty()) {
            parts.push_back(part);
        }
    }
    return parts;
}

步骤2:递归字段定位与赋值实现

编写递归函数,从根结构体开始,根据路径层级逐层匹配字段名:

  • 如果是最后一层路径,直接给double字段赋值
  • 如果是中间层级,找到对应的嵌套结构体字段,递归进入下一层
#include <boost/pfr.hpp>
#include <unordered_map>
#include <stdexcept>

namespace detail {
    // 递归终止条件:处理double类型字段
    template <typename T>
    std::enable_if_t<std::is_same_v<T, double>>
    assign_field(T& field, const std::vector<std::string>& path, size_t idx, const std::unordered_map<std::string, double>& hashmap) {
        if (idx != path.size() - 1) {
            throw std::invalid_argument("Invalid path for double field");
        }
        // 拼接完整路径作为键查找
        std::string full_path;
        for (size_t i = 0; i < path.size(); ++i) {
            if (i > 0) full_path += ".";
            full_path += path[i];
        }
        auto it = hashmap.find(full_path);
        if (it == hashmap.end()) {
            throw std::out_of_range("Field not found in hashmap: " + full_path);
        }
        field = it->second;
    }

    // 递归处理结构体类型字段
    template <typename T>
    std::enable_if_t<!std::is_same_v<T, double>>
    assign_field(T& struct_obj, const std::vector<std::string>& path, size_t idx, const std::unordered_map<std::string, double>& hashmap) {
        if (idx >= path.size()) {
            throw std::invalid_argument("Path exceeds struct depth");
        }
        const std::string& current_field_name = path[idx];
        bool field_found = false;

        // 遍历当前结构体的所有字段,匹配名称
        boost::pfr::for_each_field_with_name(struct_obj, [&](auto& field, const char* name) {
            if (current_field_name == name) {
                assign_field(field, path, idx + 1, hashmap);
                field_found = true;
            }
        });

        if (!field_found) {
            throw std::out_of_range("Struct field not found: " + current_field_name);
        }
    }
}

// 对外接口函数
template <typename Struct>
void from_hashmap(Struct& obj, const std::unordered_map<std::string, double>& hashmap) {
    // 遍历哈希表的每个键值对,逐个还原字段
    for (const auto& [path_str, value] : hashmap) {
        auto path_parts = split_path(path_str);
        if (path_parts.empty()) continue;
        detail::assign_field(obj, path_parts, 0, hashmap);
    }
}

步骤3:使用示例

假设你的Person结构体定义如下:

struct Address {
    double lat;
    double lng;
};

struct Person {
    double age;
    Address addr;
};

还原代码示例:

#include <iostream>

int main() {
    std::unordered_map<std::string, double> hashmap = {
        {"age", 30.0},
        {"addr.lat", 40.7128},
        {"addr.lng", -74.0060}
    };

    Person p;
    try {
        from_hashmap(p, hashmap);
        std::cout << "Age: " << p.age << "\n";
        std::cout << "Lat: " << p.addr.lat << ", Lng: " << p.addr.lng << "\n";
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n";
    }
    return 0;
}

关键说明

  • 反射能力依赖:完全复用boost::pfr的编译期反射,不需要手动编写字段映射,支持任意层级的嵌套结构体(只要所有最终字段都是double)
  • 错误处理:加入了路径无效、字段不存在等异常抛出,你可以根据需求改为返回bool或其他错误处理方式
  • 路径匹配:严格按照哈希表键的层级路径匹配结构体字段,确保序列化和反序列化的一致性

内容的提问来源于stack exchange,提问作者Tom McLean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 03:16:06