唯一命名对象表

时间:2018-08-02 18:09:24

标签: c++ hashmap c++14

我想列出

struct object {
    std::string unique_name;
    some_type more_data;
    other_type member_functions() const; // many such member functions
};

使用unique_name作为索引。不幸的是,我不能使用

using object_table = std::unordered_set<object>;

由于无法搜索具有名称的对象,因为object_table::find()仅允许输入object类型的搜索键:

class objects {
    object_table _table;
  public:
    object const&operator[](std::string const&name) const
    {
        // cannot be implemented using object_table::find()
    }
};

那我该怎么办?

到目前为止,我的尴尬解决方案是

using object_table = std::unordered_map<std::string, some_type>;

struct object : object_table::value_type
{
    std::string const&name() const { return first; }
    other_type member_functions() const;
  private:
    using object_table::value_type::first;
    using object_table::value_type::second;
};

class objects {
    object_table _table;
  public:
    object const&operator[](std::string const&name) const
    {
        auto it = _table.find(name);
        if(it == _table.end())
            throw runtime_error("cannot find object '"+name+'\'');
        return *static_cast<const object*>(std::addressof(*it));  // is cast legal?
    } 
};

这样做的代价是将objectstd::pair<std::string, some_type>一起麻烦地修补在一起。

1 个答案:

答案 0 :(得分:3)

由于每个对象的名称都是唯一的,因此您只能将unique_name的哈希值用作对象的哈希值。使用

namespace std
{
    template<> struct hash<object>
    {
        typedef object argument_type;
        typedef std::size_t result_type;
        result_type operator()(argument_type const& o) const noexcept
        {
            return std::hash<std::string>{}(o.unique_name);
        }
    };
}

bool operator ==(const object& lhs, const object& rhs)
{
    return lhs.unique_name == rhs.unique_name;
}

可以让您编写类似

的查找代码
using object_table = std::unordered_set<object>;

class objects 
{
    object_table _table;
  public:
    object const&operator[](std::string const&name) const
    {
        if (auto it = object_table.find(object{name}); it != object_table.end())
            return *it
        else
            throw();
    }
};

这确实要求object可以从单个std::string进行构造,并且必须用于初始化unique_name