I have a tree structure that internally uses unordered map
#include <unordered_map>
struct Node {
std::unordered_map<int, Node> children;
};
int main() {
Node a;
}
It works just fine on Apple clang 11.0.3 and MSVC v19.24, but it fails to compile on clang 10.0.0 and gcc 10.1
While regular std::map
works just fine on all compilers. I failed to find the reason for this discrepancy. Is there any way to use std::unordered_map
as a value for itself? Or pointers is the only solution here?
Here's the compiler explorer link https://godbolt.org/z/6eYch9
Here's an error from gcc:
#3 with x86-64 gcc 10.1 In file included from /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/unordered_map:43, from <source>:1: /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/stl_pair.h: In instantiation of 'struct std::pair<const int, Node>': /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/ext/aligned_buffer.h:91:28: required from 'struct __gnu_cxx::__aligned_buffer<std::pair<const int, Node> >' /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/hashtable_policy.h:233:43: required from 'struct std::__detail::_Hash_node_value_base<std::pair<const int, Node> >' /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/hashtable_policy.h:279:12: required from 'struct std::__detail::_Hash_node<std::pair<const int, Node>, false>' /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/hashtable_policy.h:1973:13: required from 'struct std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const int, Node>, false> > >' /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/hashtable.h:173:11: required from 'class std::_Hashtable<int, std::pair<const int, Node>, std::allocator<std::pair<const int, Node> >, 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> >' /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/unordered_map.h:105:18: required from 'class std::unordered_map<int, Node>' <source>:4:39: required from here /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/stl_pair.h:218:11: error: 'std::pair<_T1, _T2>::second' has incomplete type 218 | _T2 second; ///< The second member | ^~~~~~ <source>:3:8: note: forward declaration of 'struct Node' 3 | struct Node { | ^~~~ Compiler returned: 1
Iterating over a map by using STL Iterator: By creating an iterator of std::map and initializing it to the starting of map and visiting upto the end of map we can successfully iterate over all the elements of map.
But if we consider the worst case (i.e. when the hashing function is not good), the time complexity for all the operations in an unordered_map is O(n). While the worst case time complexity for all the operations in a map is O(log(n)). Hence, in the worst case scenario, a map is faster than an unordered_map.
When it comes to efficiency, there is a huge difference between maps and unordered maps. We must know the internal working of both to decide which one is to be used. You need ordered data. You would have to print/access the data (in sorted order).
Summary: all practical implementations of std::unordered_set (or unordered_map ) undoubtedly use collision chaining.
STL containers are not required to work with incomplete types. If you don't mind extra indirection, then the workaround is std::map<int, std::unique_ptr<Node>>
It's the same problem as doing e.g.
struct Node
{
Node child; // An instance of the full structure
};
You can't use a structure (or class) before it's fully defined, which it is at the closing }
.
You can however define pointers to the structure, because then the compiler don't need the full structure definition, only know the name of the structure:
struct Node
{
Node* child; // Pointer to the structure
};
So to solve your problem, you need a map of pointers:
std::unordered_map<int, Node*> children;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With