首页 > 解决方案 > 结构键和 getter 函数的哈希映射

问题描述

我有一个嵌套结构(简化):

struct Person {
  struct JobDetails {
    std::string company_name;
    std::string address;
  };

  JobDetails job_details;
  int32_t age;
  std::string name;
};

是否可以为每个结构字段创建键和 getter(函数)的哈希映射,即使是嵌套字段?

例如

std::unordered_map<std::string, ???> hash_map{
  "company_name", [](Person const& person) { return person.job_details.company_name; },
  "age", [](Person const& person) { return person.age }
};

auto value = hash_map["company_name"](person);

标签: c++c++20

解决方案


有些。您希望std::function<something>作为地图的值类型能够存储各种 lambda。更难的问题是每个表达式都必须具有在编译时已知的单一类型。如果我有 a std::string key;,那么表达式hash_map[key](person)可以是 astd::string或 an int32_t,或者可能是其他类型。

也许您可以使用字符串属性函数的映射、数字属性函数的不同映射以及更多(如果需要)。

或者,如果您真的想要一个存储多种值类型的映射,astd::variant可能会有所帮助。

using PersonProperty = std::variant<std::string, std::int32_t>; // more?
using PersonPropertyGetter = std::function<PersonProperty(Person const&)>;
std::unordered_map<std::string, PersonPropertyGetter> hash_map{
    { "company_name", [](Person const& person) { return person.job_details.company_name; } },
    { "age", [](Person const& person) { return person.age } }
};

然后你需要使用std::visitorstd::getstd::get_if来实际使用std::variant.

std::visit([&prop_name](auto const& value)
                { std::cout << prop_name << ": " << value; },
           hash_map[prop_name]);
std::visit(overloaded{
    [](std::string const&) { std::cout << " (string)\n"; },
    [](int32_t) { std::cout << " (int32_t)\n"; } });
auto prop_value = hash_map[prop_name];
if (std::string const* str_value = std::get_if<std::string>(prop_value))
    do_a_string_thing(*str_value);
int32_t age = std::get<int32_t>(hash_map["age"](person)); // Throws if wrong type!

一个示例中使用的overloaded工具在 cppreference 页面的示例中定义std::visit。只需放入一个方便的头文件:

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

推荐阅读