使用unordered_map,其中Key是T的成员 [英] Using an unordered_map where Key is a member of 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屋!