如何使用 boost::fpr::for_each_field_with_name 实现嵌套结构的哈希图

问题描述 投票:0回答:1

我想创建一个方法来进出嵌套结构,每个结构只保存双精度值,如下所示:

struct Location {
    double lat;
    double lon;
};


struct Person {
    double height;
    double age;
    double weight;
    Location location;
};

int main()
{
    // Create a Person instance
    Person person = {1.75, 30, 70, {1, 2}};

    std::unordered_map<std::string, double> hashmap;
    to_hashmap(person, hashmap);
    
    std::cout << "Hashmap Values:\n";
    for (const auto& [key, val] : hashmap) {
        std::cout << key << ": " << val << std::endl;
    }

    // // // Reconstruct struct from hashmap
    Person restored_person = from_hashmap<Person>(hashmap);
    
    std::cout << "Restored Person:\n";
    std::cout << "Height: " << restored_person.height << "\n";
    std::cout << "Age: " << restored_person.age << "\n";
    std::cout << "Weight: " << restored_person.weight << "\n";
    std::cout << "Location - Latitude: " << restored_person.location.lat << "\n";
    std::cout << "Location - Longitude: " << restored_person.location.lon << "\n";

    return 0;
}

我有将嵌套结构转换为哈希图的代码,该代码工作正常(注释掉结构重组代码),如下所示:

#include <iostream>
#include <boost/pfr.hpp>
#include <boost/pfr/core_name.hpp>


// Helper function to check if a type is a struct (excluding built-in types)
template <typename T>
constexpr bool is_struct_v = !std::is_fundamental_v<std::decay_t<T>> && !std::is_pointer_v<std::decay_t<T>> && !std::is_reference_v<std::decay_t<T>>;

// Helper function to check if a type is double
template <typename T>
constexpr bool is_double_v = std::is_same_v<std::decay_t<T>, double>;

template <typename T>
concept DefaultConstructible = std::is_default_constructible_v<T>;

template <typename T>
void to_hashmap(const T& value, std::unordered_map<std::string, double>& result, const std::string& prefix = "");

template <typename T>
void to_hashmap(const T& value, std::unordered_map<std::string, double>& result, const std::string& prefix) {
    boost::pfr::for_each_field_with_name(value, [&](std::string_view name, const auto& field_value) {
        // Create the full name by combining the prefix with the current field name
        std::string full_name = prefix.empty() ? std::string(name) : prefix + "." + std::string(name);
        
        std::cout << "Processing field: " << full_name << std::endl;

        if constexpr (is_struct_v<decltype(field_value)>) {
            // Recursively call to_hashmap for nested structs
            to_hashmap(field_value, result, full_name);
        } else if constexpr (is_double_v<decltype(field_value)>) {
            // Only assign if the field is a double
            result[full_name] = field_value;
        } else {
            std::cout << "Skipping field: " << full_name << " (not double)" << std::endl;
        }
    });
}

将结构体转换为哈希图,输出:

Processing field: height
Processing field: age
Processing field: weight
Processing field: location
Processing field: location.lat
Processing field: location.lon
Hashmap Values:
height: 1.75
age: 30
location.lat: 1
weight: 70
location.lon: 2

然而,我正在努力写出相反的内容。是否可以编写一个 from_hashmap 方法来使用

boost::fpr::for_each_field_with_name
将值的哈希图转换为结构。

(注意,boost::fpr::for_each_field_with_name 尚未在 boost 中,您必须在 https://github.com/boostorg/pfr 克隆并复制

/include
中的 boost 文件夹)

c++ boost
1个回答
0
投票

我有一个方法可以工作,制作一个可以处理不同预期类型的结构:

struct from_hashmap_handle_type {
    // Handle case when the field is a double
    template<typename T>
    void handle_double(const std::string& key, const std::unordered_map<std::string, double>& hashmap, T& field_value) {
        auto it = hashmap.find(key);
        if (it != hashmap.end()) {
            field_value = it->second;
        }
    }

    // Handle case when the field is a class type (using recursion)
    template<typename T>
    void handle_class(const std::string& key, const std::unordered_map<std::string, double>& hashmap, T& field_value) {
        boost::pfr::for_each_field_with_name(field_value, [&](std::string_view name, auto& class_field_value) {
            std::string full_name = key.empty() ? std::string(name) : key + "." + std::string(name);
            handle_field(full_name, hashmap, class_field_value);
        });
    }

    // Main dispatcher function to determine the type
    template<typename T>
    void handle_field(const std::string& key, const std::unordered_map<std::string, double>& hashmap, T& field_value) {
        if constexpr (std::is_same_v<T, double>) {
            handle_double(key, hashmap, field_value);
        } else {
            handle_class(key, hashmap, field_value);
        }
    }
};

template <typename T>
void from_hashmap(const std::unordered_map<std::string, double>& hashmap, T& result) {
    from_hashmap_handle_type handler;

    boost::pfr::for_each_field_with_name(result, [&](std::string_view name, auto& field_value) {
        std::string key = std::string(name);
        handler.handle_field(key, hashmap, field_value);
    });
}

然后你可以这样称呼...

    Person restored_person;
    from_hashmap(hashmap, restored_person);
    
    std::cout << "\nRestored Person:\n";
    std::cout << "Height: " << restored_person.height << "\n";
    std::cout << "Age: " << restored_person.age << "\n";
    std::cout << "Weight: " << restored_person.weight << "\n";
    std::cout << "Location - Latitude: " << restored_person.location.lat << "\n";
    std::cout << "Location - Longitude: " << restored_person.location.lon << "\n";
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.