添加自定义哈希函数时,C++ 无序映射需要复制构造函数

The*_*ine 3 c++ hash unordered-map copy-constructor c++17

我正在尝试对类使用自定义哈希结构A,该类是 an 中的关键类型,它是class 中的替代方案std::unordered_map之一。\n这是我的代码的简化版本,可以在其中重现错误:std::variantB

\n
#include <initializer_list>\n#include <string>\n#include <unordered_map>\n#include <variant>\n\nnamespace myNamespace {\n    class A;\n    struct AHasher;\n    class B;\n\n    // ....\n\n    class A {\n        public:\n            A(const std::string& str);\n            friend bool operator==(const A& lhs, const A& rhs);\n        public:\n            std::string value;\n    };\n\n    struct AHasher {\n        std::size_t operator()(const A& str) const;\n    };\n\n    class B {\n        public:\n            B();\n            B(const std::string& str);\n            B(const A& str);\n            B(const std::initializer_list<std::pair<const A, B>> list);\n        private:\n            std::variant<A, std::unordered_map<A, B, AHasher>> value;\n    };\n\n}  // namespace myNamespace \n\n// .......\n\nnamespace myNamespace {\n    A::A(const std::string& str) : value(str) {}\n    bool operator==(const A& lhs, const A& rhs) { \n        return lhs.value == rhs.value;\n    }\n\n    std::size_t AHasher::operator()(const A& str) const {\n        std::hash<std::string> hasher;\n        return hasher(str.value);\n    }\n   \n    B::B() : value(std::unordered_map<A, B, AHasher>{}) {}\n    B::B(const std::string& str) : value(A(str)) {}\n    B::B(const A& str) : value(str) {}\n    B::B(const std::initializer_list<std::pair<const A, B>> list) : value(list) {}\n\n} // namespace myNamespace \n\n\nint main() {\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我正在使用 GCC 9.4.0 进行编译,命令为: g++ -std=c++17 -Wall -Wextra -pedantic -O0 main.cpp\n编译失败,并显示以下消息:

\n
In file included from /usr/include/c++/9/bits/stl_algobase.h:64,\n                 from /usr/include/c++/9/bits/char_traits.h:39,\n                 from /usr/include/c++/9/string:40,\n                 from tmp.cpp:53:\n/usr/include/c++/9/bits/stl_pair.h: In instantiation of \xe2\x80\x98struct std::pair<const myNamespace::A, myNamespace::B>\xe2\x80\x99:\n/usr/include/c++/9/ext/aligned_buffer.h:91:28:   required from \xe2\x80\x98struct __gnu_cxx::__aligned_buffer<std::pair<const myNamespace::A, myNamespace::B> >\xe2\x80\x99\n/usr/include/c++/9/bits/hashtable_policy.h:233:43:   required from \xe2\x80\x98struct std::__detail::_Hash_node_value_base<std::pair<const myNamespace::A, myNamespace::B> >\xe2\x80\x99\n/usr/include/c++/9/bits/hashtable_policy.h:264:12:   required from \xe2\x80\x98struct std::__detail::_Hash_node<std::pair<const myNamespace::A, myNamespace::B>, true>\xe2\x80\x99\n/usr/include/c++/9/bits/hashtable_policy.h:2027:13:   required from \xe2\x80\x98struct std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const myNamespace::A, myNamespace::B>, true> > >\xe2\x80\x99\n/usr/include/c++/9/bits/hashtable.h:173:11:   required from \xe2\x80\x98class std::_Hashtable<myNamespace::A, std::pair<const myNamespace::A, myNamespace::B>, std::allocator<std::pair<const myNamespace::A, myNamespace::B> >, std::__detail::_Select1st, std::equal_to<myNamespace::A>, myNamespace::AHasher, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >\xe2\x80\x99\n/usr/include/c++/9/bits/unordered_map.h:105:18:   [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]\n/usr/include/c++/9/type_traits:901:12:   required from \xe2\x80\x98struct std::__is_copy_constructible_impl<std::unordered_map<myNamespace::A, myNamespace::B, myNamespace::AHasher>, true>\xe2\x80\x99\n/usr/include/c++/9/type_traits:907:12:   required from \xe2\x80\x98struct std::is_copy_constructible<std::unordered_map<myNamespace::A, myNamespace::B, myNamespace::AHasher> >\xe2\x80\x99\n/usr/include/c++/9/type_traits:2918:25:   required from \xe2\x80\x98constexpr const bool std::is_copy_constructible_v<std::unordered_map<myNamespace::A, myNamespace::B, myNamespace::AHasher> >\xe2\x80\x99\n/usr/include/c++/9/variant:275:5:   required from \xe2\x80\x98constexpr const bool std::__detail::__variant::_Traits<myNamespace::A, std::unordered_map<myNamespace::A, myNamespace::B, myNamespace::AHasher, std::equal_to<myNamespace::A>, std::allocator<std::pair<const myNamespace::A, myNamespace::B> > > >::_S_copy_ctor\xe2\x80\x99\n/usr/include/c++/9/variant:1228:11:   required from \xe2\x80\x98class std::variant<myNamespace::A, std::unordered_map<myNamespace::A, myNamespace::B, myNamespace::AHasher, std::equal_to<myNamespace::A>, std::allocator<std::pair<const myNamespace::A, myNamespace::B> > > >\xe2\x80\x99\ntmp.cpp:81:64:   required from here\n/usr/include/c++/9/bits/stl_pair.h:215:11: error: \xe2\x80\x98std::pair<_T1, _T2>::second\xe2\x80\x99 has incomplete type\n  215 |       _T2 second;                /// @c second is a copy of the second object\n      |           ^~~~~~\ntmp.cpp:74:11: note: forward declaration of \xe2\x80\x98class myNamespace::B\xe2\x80\x99\n   74 |     class B {\n      |           ^\n
Run Code Online (Sandbox Code Playgroud)\n

为什么我会在这里收到有关复制构造函数的消息?据我了解,如果我没有明确创建自己的构造函数,编译器将生成默认的复制和移动构造函数

\n

在使用此实现之前,std::unordered_map我不是在类中使用std::map具有适当运算符重载的A,并且一切正常

\n

Sam*_*hik 5

提到复制构造函数是为了转移注意力。生成复制构造函数之一时发生错误,但该错误与复制构造函数无关:

\n
\n

错误:\xe2\x80\x98std::pair<_T1, _T2>::second\xe2\x80\x99 类型不完整

\n
\n

该错误是不完整的类型。你的B包含 astd::unordered_map本身包含B. 直到其右大括号为止,的定义B才完整;因此B,当无序映射声明不完整时,它是前向声明。

\n

关于哪些容器可以使用容器值的不完整类来定义,并且只需要在实际使用时定义,C++ 标准的各个修订版中存在差异。这是一个单独的问题,但就您关于复制构造函数与其中任何一个有什么关系的问题而言,答案是它没有。

\n