c++ - 包装 unordered_map 以构建不可修改(不可变)的映射

标签 c++ unordered-map container-data-type

我正在研究容器类型,深入了解细节并尝试构建不可修改(或不可变)的 map 。

为此,我构建了某种类似复制构造函数的类型,将另一个 unordered_map 中的所有元素添加到我的 UnmodifyingMap 中(这基本上是 std::unordered_map 的包装器)。为了使其不可修改,我只提供 const 迭代器和只读方法。但我被构造函数困住了,我确信我错过了一些东西,也许有人可以指出我这里的问题。也许这是一个完全错误的方式,但他是迄今为止尝试过的:

template <typename Key, typename T,
    typename HashFcn = std::hash<Key>,
    typename EqualKey = std::equal_to<Key>,
    typename Alloc = std::allocator<std::pair<const Key, T> > > 
class UnmodifiableMap {
public:
    // The actual data
    typedef std::unordered_map<T, Key, HashFcn, EqualKey> base;

    typedef Key key_type;
    typedef T data_type;
    typedef T mapped_type;
    typedef std::pair<const key_type, data_type> value_type;
    typedef HashFcn hasher;
    typedef EqualKey key_equal;
    typedef Alloc allocator_type;

    typedef typename base::size_type size_type;
    typedef typename base::const_iterator const_iterator;
    typedef typename base::iterator iterator;

private:
    base _map;

    /**
     * Constructs an empty unordered_map 
     */
    UnmodifiableMap(
        size_type n = 0, const hasher& hf = hasher(),
        const key_equal& eql = key_equal(),
        const allocator_type &alloc = allocator_type())
            : _map(n, hf, eql, alloc) {}

public:
    /** Constructs a copy of unordered_map */
    UnmodifiableMap(const base& other)
    : _map(static_cast<const base&>(other)) {}

    ~UnmodifiableMap() {}   

    iterator begin() { return _map.begin(); }
    iterator end() { return _map.end(); }
    const_iterator begin() const { return _map.begin(); }
    const_iterator end() const { return _map.end(); }

    bool empty() const { return _map.empty(); }

    bool contains(const key_type& key) const { 
        return _map.find(key) != _map.end(); }
};

这里是正文:

int main(int argc, char **argv) {
    typedef std::unordered_map<int, std::string> Items;
    Items map;

    map[1] = "first string";
    map[4] = "string 4";
    map[5] = "string 5";
    map[22] = "string 22";
    map[12] = "string 12";
    map[18] = "string 18";

    typedef UnmodifiableMap<int, std::string> ReadOnlyItems;
    ReadOnlyItems readonlymap(map);

    return 0;
}

我得到的错误是

Unmodifiable_map.cpp: In function ‘int main(int, char**)’:
Unmodifiable_map.cpp:56:25: error: no matching function for call to ‘UnmodifiableMap<int, std::basic_string<char> >::UnmodifiableMap(Items&)’
Unmodifiable_map.cpp:56:25: note: candidates are:
Unmodifiable_map.h:45:2: note: UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::UnmodifiableMap(const base&) [with Key = int, T = std::basic_string<char>, HashFcn = std::hash<int>, EqualKey = std::equal_to<int>, Alloc = std::allocator<std::pair<const int, std::basic_string<char> > >, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::base = std::unordered_map<std::basic_string<char>, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const std::basic_string<char>, int> > >]
Unmodifiable_map.h:45:2: note:   no known conversion for argument 1 from ‘Items {aka std::unordered_map<int, std::basic_string<char> >}’ to ‘const base& {aka const std::unordered_map<std::basic_string<char>, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const std::basic_string<char>, int> > >&}’
Unmodifiable_map.h:37:2: note: UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::UnmodifiableMap(UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::size_type, const hasher&, const key_equal&, const allocator_type&) [with Key = int, T = std::basic_string<char>, HashFcn = std::hash<int>, EqualKey = std::equal_to<int>, Alloc = std::allocator<std::pair<const int, std::basic_string<char> > >, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::size_type = long unsigned int, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::hasher = std::hash<int>, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::key_equal = std::equal_to<int>, UnmodifiableMap<Key, T, HashFcn, EqualKey, Alloc>::allocator_type = std::allocator<std::pair<const int, std::basic_string<char> > >]
Unmodifiable_map.h:37:2: note:   no known conversion for argument 1 from ‘Items {aka std::unordered_map<int, std::basic_string<char> >}’ to ‘long unsigned int’
Unmodifiable_map.h:14:7: note: UnmodifiableMap<int, std::basic_string<char> >::UnmodifiableMap(const UnmodifiableMap<int, std::basic_string<char> >&)
Unmodifiable_map.h:14:7: note:   no known conversion for argument 1 from ‘Items {aka std::unordered_map<int, std::basic_string<char> >}’ to ‘const UnmodifiableMap<int, std::basic_string<char> >&’
Unmodifiable_map.h:14:7: note: UnmodifiableMap<int, std::basic_string<char> >::UnmodifiableMap(UnmodifiableMap<int, std::basic_string<char> >&&)
Unmodifiable_map.h:14:7: note:   no known conversion for argument 1 from ‘Items {aka std::unordered_map<int, std::basic_string<char> >}’ to ‘UnmodifiableMap<int, std::basic_string<char> >&&’

希望有人能对此有所启发。另外,我认为我需要在复制构造函数中做更多的事情,适本地复制元素(如 swap 函数)和 operator= 的实现?!

最佳答案

您正在交换 T 的角色和Key在你的base包装类中的类型定义:

template <typename Key, typename T,
    typename HashFcn = std::hash<Key>,
    typename EqualKey = std::equal_to<Key>,
    typename Alloc = std::allocator<std::pair<const Key, T> > > 
class UnmodifiableMap {
public:
    // typedef std::unordered_map<T, Key, HashFcn, EqualKey> base; // ERROR
    typedef std::unordered_map<Key, T, HashFcn, EqualKey> base; // OK
    ...

因此,您的底层 map 最终成为 unordered_map<string, int>而不是unordered_map<int, string> ,并且编译器提示不匹配。

另请注意,您有一个不必要的 static_cast在你的构造函数中:

UnmodifiableMap(const base& other)
// : _map(static_cast<const base&>(other)) {} // NOT NEEDED. Just do:
   : _map(other) {}

关于c++ - 包装 unordered_map 以构建不可修改(不可变)的映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14896841/

相关文章:

c++ - 将许多值映射到 boost::unordered_map 中的单个键?

c++ - STL 中是否有排序容器?

c++ - 获取类似 STL 的嵌套容器中的元素总数

C++ `ifdef` 与宏值的串联

c++ - 使用模板可以对类型(std::plus,std::minus)之类的对称关系建模吗?

c++ - 在 C++ 代码中使用 C 定义的结构

c++ - `std::unordered_map` 没有复制关键数据

c++ - std::unordered_map 如何从桶中返回正确的值

c++ - 未解析的外部符号 "public: void __thiscall..."

c++ - 标准库/模板容器的 const 语义的经验法则?