我想创建一个方法来进出嵌套结构,每个结构只保存双精度值,如下所示:
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 文件夹)
我有一个方法可以工作,制作一个可以处理不同预期类型的结构:
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";