[#compliance] = Standard Compliance :idprefix: compliance_ :cpp: C++ == Closed-addressing containers `unordered_[multi]set` and `unordered_[multi]map` are intended to provide a conformant implementation of the {cpp}20 standard that will work with {cpp}98 upwards. This wide compatibility does mean some compromises have to be made. With a compiler and library that fully support {cpp}11, the differences should be minor. === Move emulation Support for move semantics is implemented using Boost.Move. If rvalue references are available it will use them, but if not it uses a close, but imperfect emulation. On such compilers: * Non-copyable objects can be stored in the containers. They can be constructed in place using `emplace`, or if they support Boost.Move, moved into place. * The containers themselves are not movable. * Argument forwarding is not perfect. === Use of allocators {cpp}11 introduced a new allocator system. It's backwards compatible due to the lax requirements for allocators in the old standard, but might need some changes for allocators which worked with the old versions of the unordered containers. It uses a traits class, `allocator_traits` to handle the allocator adding extra functionality, and making some methods and types optional. During development a stable release of `allocator_traits` wasn't available so an internal partial implementation is always used in this version. Hopefully a future version will use the standard implementation where available. The member functions `construct`, `destroy` and `max_size` are now optional, if they're not available a fallback is used. A full implementation of `allocator_traits` requires sophisticated member function detection so that the fallback is used whenever the member function call is not well formed. This requires support for SFINAE expressions, which are available on GCC from version 4.4 and Clang. On other compilers, there's just a test to see if the allocator has a member, but no check that it can be called. So rather than using a fallback there will just be a compile error. `propagate_on_container_copy_assignment`, `propagate_on_container_move_assignment`, `propagate_on_container_swap` and `select_on_container_copy_construction` are also supported. Due to imperfect move emulation, some assignments might check `propagate_on_container_copy_assignment` on some compilers and `propagate_on_container_move_assignment` on others. === Construction/Destruction using allocators The following support is required for full use of {cpp}11 style construction/destruction: * Variadic templates. * Piecewise construction of `std::pair`. * Either `std::allocator_traits` or expression SFINAE. This is detected using Boost.Config. The macro `BOOST_UNORDERED_CXX11_CONSTRUCTION` will be set to 1 if it is found, or 0 otherwise. When this is the case `allocator_traits::construct` and `allocator_traits::destroy` will always be used, apart from when piecewise constructing a `std::pair` using `boost::tuple` (see <>), but that should be easily avoided. When support is not available `allocator_traits::construct` and `allocator_traits::destroy` are never called. === Pointer Traits `pointer_traits` aren't used. Instead, pointer types are obtained from rebound allocators, this can cause problems if the allocator can't be used with incomplete types. If `const_pointer` is not defined in the allocator, `boost::pointer_to_other::type` is used to obtain a const pointer. === Pairs Since the containers use `std::pair` they're limited to the version from the current standard library. But since {cpp}11 ``std::pair``'s `piecewise_construct` based constructor is very useful, `emplace` emulates it with a `piecewise_construct` in the `boost::unordered` namespace. So for example, the following will work: [source,c++] ---- boost::unordered_multimap x; x.emplace( boost::unordered::piecewise_construct, boost::make_tuple("key"), boost::make_tuple(1, 2)); ---- Older drafts of the standard also supported variadic constructors for `std::pair`, where the first argument would be used for the first part of the pair, and the remaining for the second part. === Miscellaneous When swapping, `Pred` and `Hash` are not currently swapped by calling `swap`, their copy constructors are used. As a consequence when swapping an exception may be thrown from their copy constructor. Variadic constructor arguments for `emplace` are only used when both rvalue references and variadic template parameters are available. Otherwise `emplace` can only take up to 10 constructors arguments. == Open-addressing containers The C++ standard does not currently provide any open-addressing container specification to adhere to, so `boost::unordered_flat_set`/`unordered_node_set` and `boost::unordered_flat_map`/`unordered_node_map` take inspiration from `std::unordered_set` and `std::unordered_map`, respectively, and depart from their interface where convenient or as dictated by their internal data structure, which is radically different from that imposed by the standard (closed addressing). Open-addressing containers provided by Boost.Unordered only work with reasonably compliant C++11 (or later) compilers. Language-level features such as move semantics and variadic template parameters are then not emulated. The containers are fully https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^]. The main differences with C++ unordered associative containers are: * In general: ** `begin()` is not constant-time. ** `erase(iterator)` returns `void` instead of an iterator to the following element. ** There is no API for bucket handling (except `bucket_count`). ** The maximum load factor of the container is managed internally and can't be set by the user. The maximum load, exposed through the public function `max_load`, may decrease on erasure under high-load conditions. * Flat containers (`boost::unordered_flat_set` and `boost::unordered_flat_map`): ** `value_type` must be move-constructible. ** Pointer stability is not kept under rehashing. ** There is no API for node extraction/insertion. //-