this is a regression in newer point-releases of gcc (this bug got backported). it appears first in 10.4, 11.2.1 and 12.x. 10.3 and 11.2.0 do not have this issue. #include <unordered_map> #include <memory> struct key {}; struct foo { struct my_hash { my_hash(int i = 42) {} std::size_t operator()(const key &ep) const { return 0; } }; private: std::unordered_map<key, std::weak_ptr<std::string>, foo::my_hash> things_{}; }; <source>:15:79: error: use of deleted function 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() [with _Key = key; _Tp = std::weak_ptr<std::__cxx11::basic_string<char> >; _Hash = foo::my_hash; _Pred = std::equal_to<key>; _Alloc = std::allocator<std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > > >]' 15 | std::unordered_map<key, std::weak_ptr<std::string>, foo::my_hash> things_{}; | ^ In file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/unordered_map:47, from <source>:1: /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/unordered_map.h:141:7: note: 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() [with _Key = key; _Tp = std::weak_ptr<std::__cxx11::basic_string<char> >; _Hash = foo::my_hash; _Pred = std::equal_to<key>; _Alloc = std::allocator<std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > > >]' is implicitly deleted because the default definition would be ill-formed: 141 | unordered_map() = default; | ^~~~~~~~~~~~~ /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/unordered_map.h:141:7: error: use of deleted function 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::_Hashtable() [with _Key = key; _Value = std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > >; _Alloc = std::allocator<std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<key>; _Hash = foo::my_hash; _RangeHash = std::__detail::_Mod_range_hashing; _Unused = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, false, true>]' In file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/unordered_map:46: /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/hashtable.h:529:7: note: 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::_Hashtable() [with _Key = key; _Value = std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > >; _Alloc = std::allocator<std::pair<const key, std::weak_ptr<std::__cxx11::basic_string<char> > > >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<key>; _Hash = foo::my_hash; _RangeHash = std::__detail::_Mod_range_hashing; _Unused = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, false, true>]' is implicitly deleted because the default definition would be ill-formed: 529 | _Hashtable() = default; | ^~~~~~~~~~ /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/hashtable.h:529:7: error: use of deleted function 'constexpr std::_Enable_default_constructor<false, _Tag>::_Enable_default_constructor() [with _Tag = std::__detail::_Hash_node_base]' In file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/hashtable.h:36: /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/enable_special_members.h:113:15: note: declared here 113 | constexpr _Enable_default_constructor() noexcept = delete; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ Compiler returned: 1
This is another when is the inner type complete and the constructor can be used issues really.
Mainly read bug 102199 comment #7
Yes, and the standard says that instantiating std::unordered_map with incomplete types is undefined.
is it related to nested classes? this reproduces the issue: uncomment line 9 to repro: #include <unordered_map> #include <memory> struct key {}; struct my_hash { my_hash() {} //my_hash(int i = 42) {} // <<-- uncomment for bug std::size_t operator()(const key &ep) const { return 0; } }; struct foo { foo(); private: std::unordered_map<key, int, my_hash> things_; }; foo::foo() {}
oh, no. scratch that last comment.
(In reply to piersh from comment #4) > struct my_hash > { > my_hash() {} > my_hash(int i = 42) {} // <<-- uncomment for bug > std::size_t operator()(const key &ep) const { return 0; } > }; That is because my_hash constructor call with no arguments is ambigous at that point. If you define one or the other constructor, it is no longer ambigous. If you define both, the code is invalid.
*** Bug 107340 has been marked as a duplicate of this bug. ***
I understand we're in a tangled web of partially-complete class rules here, but the standard does give you the expectation that the inner class is complete at its closing brace: [class.pre] p2 says: "A class is considered defined after the closing brace of its class-specifier has been seen even though its member functions are in general not yet defined."
For the example in comment 0 the default-initializer for things_{} is the problem, removing the {} allows it to compile. For the example in Bug 107340 the problem is the default-initializer x = 0 in the nested class, removing that allows it to compile. The nested class is complete at the closing } but its complete class contexts are not complete until the enclosing class is complete. default-initializers and nested classes do not work well.