使用unordered_map,其中Key是T的成员 [英] Using an unordered_map where Key is a member of T

查看:113
本文介绍了使用unordered_map,其中Key是T的成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有什么好方法可以使用unordered_map,以便您可以在恒定时间内(平均情况)通过成员变量访问对象?下面的示例具有此功能,但需要将每个 Person 的名称复制为键:

Is there any nice way to use an unordered_map so that you can access objects by a member variable in constant time (average case)? The following example has this functionality but requires the name of each Person to be duplicated as the Key:

#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>

class Person {
 public:
  Person() : name_("") {}
  Person(const std::string& name) : name_(name) {}
  std::string getName() const { return name_; }
  void kill() const { std::cout << name_ << " is dead!" << std::endl; }
 private:
  std::string name_;
};

int main(int argc, const char* argv[]) {
  Person p1("dave");
  Person p2("bob");

  std::unordered_map<std::string, Person> map = {
    {p1.getName(), p1}, // Duplicating the
    {p2.getName(), p2}  // keys here
  };

  map["dave"].kill();
  return 0;
}

我在想, value_type 本身必须是 Person ,而不是 pair< string,Person> unordered_map 在散列和访问对象时需要知道使用 Person :: getName

I'm thinking that somehow the value_type would need to be Person itself, instead of a pair<string, Person> and the unordered_map would need to know to use Person::getName when hashing and accessing objects.

理想的解决方案将允许我设置 unordered_map (或更多 unordered_set 易于使用),知道使用 Person :: getName 来获取每个对象的密钥。然后,我可以简单地通过提供对象(而不提供键,因为它知道如何获取键)来插入它们,并通过提供与返回值等于 Person的返回值比较的键来访问它们: getName

The ideal solution would allow me to set up an unordered_map (or unordered_set if it's more apt for the job) that knows to use Person::getName to get the key of each object. I would then be able to insert them simply by giving the object (and no key because it knows how to get the key) and access them by giving keys that would compare equal to the return value of Person::getName.

类似以下内容:

// Pseudocode
std::unordered_map<Person, Person::getName> map = {p1, p2};
map["dave"].kill();

因此可以实例化 unordered_map

推荐答案

如果您不反对使用 Boost ,然后 Boost。 MultiIndex 使此操作极其简单,而不会增加任何不必要的效率低下。这是一个示例,该示例有效地创建了 Person 对象的 unordered_set ,并以的值为键Person :: getName()

If you're not opposed to using Boost, then Boost.MultiIndex makes this extremely simple without adding any needless inefficiency. Here's an example that effectively creates an unordered_set of Person objects that is keyed on the value of Person::getName():

#include <string>
#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/mem_fun.hpp>

namespace bmi = boost::multi_index;

struct Person
{
    Person() = default;
    Person(std::string const& name) : name_(name) { }
    std::string const& getName() const noexcept { return name_; }
    void kill() const { std::cout << name_ << " is dead!\n"; }

private:
    std::string name_;
};

typedef bmi::multi_index_container<
    Person,
    bmi::indexed_by<
        bmi::hashed_unique<
            bmi::const_mem_fun<Person, std::string const&, &Person::getName>
        >
    >
> PersonUnorderedSet;

int main()
{
    Person p1("dave");
    Person p2("bob");

    PersonUnorderedSet set;
    set.insert(p1);
    set.insert(p2);

    set.find("dave")->kill();

    // for exposition, find is actually returning an iterator
    PersonUnorderedSet::const_iterator iter = set.find("bob");
    if (iter != set.end())
        iter->kill();

    // set semantics -- newly_added is false here, because
    // the container already contains a Person named 'dave'
    bool const newly_added = set.insert(Person("dave")).second;
}

(请注意,我更改了 Person的签名: :getName()可以通过 const 引用返回,而不是为了效率而按值返回,但并非必须进行更改。)

(Note that I changed the signature of Person::getName() to return by const-reference rather than by value for efficiency's sake, but the change isn't strictly required.)

应该注意的是C ++ 14对透明比较器允许您在此处使用 std :: unordered_set< Person> 而不需要Boost。

It should be noted that C++14's support for transparent comparators would allow you to use std::unordered_set<Person> here without any need for Boost.

这篇关于使用unordered_map,其中Key是T的成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆