unordered_map 中用户定义的类

Posted

技术标签:

【中文标题】unordered_map 中用户定义的类【英文标题】:user defined classes in unordered map 【发布时间】:2021-02-12 13:48:46 【问题描述】:

我在 Windows 上的 VScode 上使用 C++17、MSYS2 MinGW64、OpenGL、stb_image。在下面的代码中,我试图递归搜索每个 .png 文件的特定目录以加载纹理(使用接受 std::string 参数的 Texture 对象)。当我运行我的代码时,我得到了这些错误:

C:/msys64/mingw64/include/c++/10.2.0/tuple: In instantiation of 'std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = int&&; long long unsigned int ..._Indexes1 = 0; _Args2 = ; long long unsigned int ..._Indexes2 = ; _T1 = const int; _T2 = Texture]':
C:/msys64/mingw64/include/c++/10.2.0/tuple:1678:63:   required from 'std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = int&&; _Args2 = ; _T1 = const int; _T2 = Texture]'
C:/msys64/mingw64/include/c++/10.2.0/ext/new_allocator.h:150:4:   required from 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const int, Texture>; _Args = const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>; _Tp = std::__detail::_Hash_node<std::pair<const int, Texture>, false>]'
C:/msys64/mingw64/include/c++/10.2.0/bits/alloc_traits.h:512:17:   required from 'static void std::allocator_traits<std::allocator<_Tp1> >::construct(std::allocator_traits<std::allocator<_Tp1> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<const int, Texture>; _Args = const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>; _Tp = std::__detail::_Hash_node<std::pair<const int, Texture>, false>; std::allocator_traits<std::allocator<_Tp1> >::allocator_type = std::allocator<std::__detail::_Hash_node<std::pair<const int, Texture>, false> >]'
C:/msys64/mingw64/include/c++/10.2.0/bits/hashtable_policy.h:2037:36:   required from 'std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type* std::__detail::_Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&& ...) [with _Args = 
const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>; _NodeAlloc = std::allocator<std::__detail::_Hash_node<std::pair<const int, Texture>, false> >; std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type = std::allocator<std::__detail::_Hash_node<std::pair<const int, Texture>, false> >::value_type]'
C:/msys64/mingw64/include/c++/10.2.0/bits/hashtable.h:272:35:   required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_Scoped_node::_Scoped_node(std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hashtable_alloc*, _Args&& ...) [with _Args = const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<>; _Key = int; _Value = std::pair<const int, Texture>; _Alloc = std::allocator<std::pair<const int, Texture> >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<int>; _H1 = std::hash<int>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hashtable_alloc = std::_Hashtable<int, std::pair<const int, Texture>, std::allocator<std::pair<const int, Texture> >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::__hashtable_alloc]'
C:/msys64/mingw64/include/c++/10.2.0/bits/hashtable_policy.h:739:42:   required from 'std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type& std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::operator[](std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type&&) [with _Key = int; _Pair = std::pair<const int, Texture>; _Alloc = std::allocator<std::pair<const int, Texture> >; _Equal = std::equal_to<int>; _H1 = std::hash<int>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type = Texture; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type = int]'
C:/msys64/mingw64/include/c++/10.2.0/bits/unordered_map.h:988:20:   required from 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type& std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type&&) [with _Key = int; _Tp = Texture; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, Texture> >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type = Texture; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type = int]'
src/GameUI.cpp:32:50:   required from here
C:/msys64/mingw64/include/c++/10.2.0/tuple:1689:70: error: no matching function for call to 'Texture::Texture()'
 1689 |         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)

我该如何解决这个问题?

另外,是否有任何更正或建议可以改进我的代码(尤其是 map.emplace 位)?

代码:

#include "Texture.h"
#include <string>
#include <unordered_map>
#include <filesystem>
#include <iostream>

int main() 
    std::unordered_map<int, Texture> map;
    std::string path "resources\\";
    std::string ext ".png";
    size_t count ;

    for (auto &p : std::filesystem::recursive_directory_iterator(path)) 
        if (p.path().extension() == ext) 
            map.emplace(count, Texturep.path().string()); // Is this the most efficient way?
            std::cout << p.path().string() << std::endl;
        
            
        else if (!p.is_directory())
            count++;
    
    Texture test = map[7]; // Line 32 in GameUI.cpp
    return 0;

【问题讨论】:

std::string path "resources/"; -> std::string path "resources\\"; ? Windows 应将所有正斜杠转换为反斜杠,所以我不确定这是您的问题。也许您的工作目录不是您期望的那样?你如何运行你的程序?你试过使用绝对路径吗? 对不起,你是对的,这不是问题所在。我已经稍微调整了代码,现在遇到了一个错误。问题是否在于我如何使用无序地图? GameUI.cpp 中的第 32 行? 如果您的Texture 没有默认构造函数,则不能使用无序映射operator[] 【参考方案1】:

Texture test = map[7];

map[7] 返回纹理上的引用,如果尚不存在,则默认构造它。如果 Texture 没有默认构造函数,则会出现此错误。

尝试改用map::at(),如果map[7] 不存在,则会引发异常。或者map::find(),如果你不想要例外。或者,好吧,只需定义Texture::Texture()...


map.emplace(count, Texturep.path().string()); // 这是最有效的方法吗?

我想map.emplace(count, p.path().string()) 应该够了吧?

【讨论】:

以上是关于unordered_map 中用户定义的类的主要内容,如果未能解决你的问题,请参考以下文章

使用在内部结构定义中保存函数的类成员变量,这些函数将用作 unordered_map 对象的模板参数

unordered_map使用pair

在 C++ std::unordered_map 中预分配桶

无法专门化std :: hash来存储unordered_map中的自定义类型

c++ unordered_map 自定义key

C++ 哈希表 - 如何解决 unordered_map 与自定义数据类型作为键的冲突?