[#unordered_flat_set]
== 类模板 unordered_flat_set

:idprefix: unordered_flat_set_

`boost::unordered_flat_set` — 一种开放定址无序关联容器，用于存储唯一值。

`boost::unordered_flat_set` 的性能远优于 `boost::unordered_set` 或 `std::unordered_set` 的其他实现。与基于节点的标准无序关联容器不同，`boost::unordered_flat_set` 的元素直接保存在桶数组中，当插入位置已被占用时，会转移到原始位置附近可用的桶中。这种数据布局称为**开放定址**。

由于采用开放定址，`boost::unordered_flat_set` 的接口在多个方面与 `boost::unordered_set`/`std::unordered_set` 存在差异：

- `value_type` 必须可移动构造。
- 在重哈希过程中不保持指针稳定性。
- `begin()` 不是常数时间操作。
- 没有用于桶操作的 API（除了 `bucket_count`），也没有节点提取/插入的 API。
- 容器的最大负载因子由内部管理，用户无法设置。

除此之外，`boost::unordered_flat_set` 基本上是基于节点的标准无序关联容器的直接替代品。

=== 概要

[listing,subs="+macros,+quotes"]
-----
// #include xref:reference/header_unordered_flat_set.adoc[`<boost/unordered/unordered_flat_set.hpp>`]

namespace boost {
namespace unordered {

  template<class Key,
           class Hash = boost::hash<Key>,
           class Pred = std::equal_to<Key>,
           class Allocator = std::allocator<Key>>
  class unordered_flat_set {
  public:
    // types
    using key_type             = Key;
    using value_type           = Key;
    using init_type            = Key;
    using hasher               = Hash;
    using key_equal            = Pred;
    using allocator_type       = Allocator;
    using pointer              = typename std::allocator_traits<Allocator>::pointer;
    using const_pointer        = typename std::allocator_traits<Allocator>::const_pointer;
    using reference            = value_type&;
    using const_reference      = const value_type&;
    using size_type            = std::size_t;
    using difference_type      = std::ptrdiff_t;

    using iterator             = _implementation-defined_;
    using const_iterator       = _implementation-defined_;

    using stats                = xref:reference/stats.adoc#stats_stats_type[__stats-type__]; // if statistics are xref:unordered_flat_set_boost_unordered_enable_stats[enabled]

    // construct/copy/destroy
    xref:#unordered_flat_set_default_constructor[unordered_flat_set]();
    explicit xref:#unordered_flat_set_bucket_count_constructor[unordered_flat_set](size_type n,
                                const hasher& hf = hasher(),
                                const key_equal& eql = key_equal(),
                                const allocator_type& a = allocator_type());
    template<class InputIterator>
      xref:#unordered_flat_set_iterator_range_constructor[unordered_flat_set](InputIterator f, InputIterator l,
                         size_type n = _implementation-defined_,
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& a = allocator_type());
    xref:#unordered_flat_set_copy_constructor[unordered_flat_set](const unordered_flat_set& other);
    xref:#unordered_flat_set_move_constructor[unordered_flat_set](unordered_flat_set&& other);
    template<class InputIterator>
      xref:#unordered_flat_set_iterator_range_constructor_with_allocator[unordered_flat_set](InputIterator f, InputIterator l, const allocator_type& a);
    explicit xref:#unordered_flat_set_allocator_constructor[unordered_flat_set](const Allocator& a);
    xref:#unordered_flat_set_copy_constructor_with_allocator[unordered_flat_set](const unordered_flat_set& other, const Allocator& a);
    xref:#unordered_flat_set_move_constructor_from_concurrent_flat_set[unordered_flat_set](concurrent_flat_set<Key, Hash, Pred, Allocator>&& other);
    xref:#unordered_flat_set_initializer_list_constructor[unordered_flat_set](std::initializer_list<value_type> il,
                       size_type n = _implementation-defined_
                       const hasher& hf = hasher(),
                       const key_equal& eql = key_equal(),
                       const allocator_type& a = allocator_type());
    xref:#unordered_flat_set_bucket_count_constructor_with_allocator[unordered_flat_set](size_type n, const allocator_type& a);
    xref:#unordered_flat_set_bucket_count_constructor_with_hasher_and_allocator[unordered_flat_set](size_type n, const hasher& hf, const allocator_type& a);
    template<class InputIterator>
      xref:#unordered_flat_set_iterator_range_constructor_with_bucket_count_and_allocator[unordered_flat_set](InputIterator f, InputIterator l, size_type n, const allocator_type& a);
    template<class InputIterator>
      xref:#unordered_flat_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_flat_set](InputIterator f, InputIterator l, size_type n, const hasher& hf,
                         const allocator_type& a);
    xref:#unordered_flat_set_initializer_list_constructor_with_allocator[unordered_flat_set](std::initializer_list<value_type> il, const allocator_type& a);
    xref:#unordered_flat_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_flat_set](std::initializer_list<value_type> il, size_type n,
                       const allocator_type& a);
    xref:#unordered_flat_set_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_flat_set](std::initializer_list<value_type> il, size_type n, const hasher& hf,
                       const allocator_type& a);
    xref:#unordered_flat_set_destructor[~unordered_flat_set]();
    unordered_flat_set& xref:#unordered_flat_set_copy_assignment[operator++=++](const unordered_flat_set& other);
    unordered_flat_set& xref:#unordered_flat_set_move_assignment[operator++=++](unordered_flat_set&& other) ++noexcept(
      (boost::allocator_traits<Allocator>::is_always_equal::value ||
       boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
       std::is_same<pointer, value_type*>::value);++
    unordered_flat_set& xref:#unordered_flat_set_initializer_list_assignment[operator++=++](std::initializer_list<value_type>);
    allocator_type xref:#unordered_flat_set_get_allocator[get_allocator]() const noexcept;

    // iterators
    iterator       xref:#unordered_flat_set_begin[begin]() noexcept;
    const_iterator xref:#unordered_flat_set_begin[begin]() const noexcept;
    iterator       xref:#unordered_flat_set_end[end]() noexcept;
    const_iterator xref:#unordered_flat_set_end[end]() const noexcept;
    const_iterator xref:#unordered_flat_set_cbegin[cbegin]() const noexcept;
    const_iterator xref:#unordered_flat_set_cend[cend]() const noexcept;

    // capacity
    ++[[nodiscard]]++ bool xref:#unordered_flat_set_empty[empty]() const noexcept;
    size_type xref:#unordered_flat_set_size[size]() const noexcept;
    size_type xref:#unordered_flat_set_max_size[max_size]() const noexcept;

    // modifiers
    template<class... Args> std::pair<iterator, bool> xref:#unordered_flat_set_emplace[emplace](Args&&... args);
    template<class... Args> iterator xref:#unordered_flat_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args);
    std::pair<iterator, bool> xref:#unordered_flat_set_copy_insert[insert](const value_type& obj);
    std::pair<iterator, bool> xref:#unordered_flat_set_move_insert[insert](value_type&& obj);
    template<class K> std::pair<iterator, bool> xref:#unordered_flat_set_transparent_insert[insert](K&& k);
    iterator xref:#unordered_flat_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj);
    iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
    template<class K> iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k);
    template<class InputIterator> void xref:#unordered_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last);
    void xref:#unordered_flat_set_insert_initializer_list[insert](std::initializer_list<value_type>);

    _convertible-to-iterator_     xref:#unordered_flat_set_erase_by_position[erase](iterator position);
    _convertible-to-iterator_     xref:#unordered_flat_set_erase_by_position[erase](const_iterator position);
    size_type                   xref:#unordered_flat_set_erase_by_key[erase](const key_type& k);
    template<class K> size_type xref:#unordered_flat_set_erase_by_key[erase](K&& k);
    iterator  xref:#unordered_flat_set_erase_range[erase](const_iterator first, const_iterator last);
    void      xref:#unordered_flat_set_swap[swap](unordered_flat_set& other)
      noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
               boost::allocator_traits<Allocator>::propagate_on_container_swap::value);
    init_type xref:#unordered_flat_set_pull[pull](const_iterator position);
    void      xref:#unordered_flat_set_clear[clear]() noexcept;

    template<class H2, class P2>
      void xref:#unordered_flat_set_merge[merge](unordered_flat_set<Key, T, H2, P2, Allocator>& source);
    template<class H2, class P2>
      void xref:#unordered_flat_set_merge[merge](unordered_flat_set<Key, T, H2, P2, Allocator>&& source);

    // observers
    hasher xref:#unordered_flat_set_hash_function[hash_function]() const;
    key_equal xref:#unordered_flat_set_key_eq[key_eq]() const;

    // set operations
    iterator         xref:#unordered_flat_set_find[find](const key_type& k);
    const_iterator   xref:#unordered_flat_set_find[find](const key_type& k) const;
    template<class K>
      iterator       xref:#unordered_flat_set_find[find](const K& k);
    template<class K>
      const_iterator xref:#unordered_flat_set_find[find](const K& k) const;
    size_type        xref:#unordered_flat_set_count[count](const key_type& k) const;
    template<class K>
      size_type      xref:#unordered_flat_set_count[count](const K& k) const;
    bool             xref:#unordered_flat_set_contains[contains](const key_type& k) const;
    template<class K>
      bool           xref:#unordered_flat_set_contains[contains](const K& k) const;
    std::pair<iterator, iterator>               xref:#unordered_flat_set_equal_range[equal_range](const key_type& k);
    std::pair<const_iterator, const_iterator>   xref:#unordered_flat_set_equal_range[equal_range](const key_type& k) const;
    template<class K>
      std::pair<iterator, iterator>             xref:#unordered_flat_set_equal_range[equal_range](const K& k);
    template<class K>
      std::pair<const_iterator, const_iterator> xref:#unordered_flat_set_equal_range[equal_range](const K& k) const;

    // bucket interface
    size_type xref:#unordered_flat_set_bucket_count[bucket_count]() const noexcept;

    // hash policy
    float xref:#unordered_flat_set_load_factor[load_factor]() const noexcept;
    float xref:#unordered_flat_set_max_load_factor[max_load_factor]() const noexcept;
    void xref:#unordered_flat_set_set_max_load_factor[max_load_factor](float z);
    size_type xref:#unordered_flat_set_max_load[max_load]() const noexcept;
    void xref:#unordered_flat_set_rehash[rehash](size_type n);
    void xref:#unordered_flat_set_reserve[reserve](size_type n);

    // statistics (if xref:unordered_flat_set_boost_unordered_enable_stats[enabled])
    stats xref:#unordered_flat_set_get_stats[get_stats]() const;
    void xref:#unordered_flat_set_reset_stats[reset_stats]() noexcept;
  };

  // Deduction Guides
  template<class InputIterator,
           class Hash = boost::hash<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>,
           class Pred = std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>,
           class Allocator = std::allocator<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>>
    unordered_flat_set(InputIterator, InputIterator, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type = xref:#unordered_flat_set_deduction_guides[__see below__],
                       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;

  template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
           class Allocator = std::allocator<T>>
    unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type = xref:#unordered_flat_set_deduction_guides[__see below__],
                       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_flat_set<T, Hash, Pred, Allocator>;

  template<class InputIterator, class Allocator>
    unordered_flat_set(InputIterator, InputIterator, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator)
      -> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>,
                            boost::hash<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>,
                            std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;

  template<class InputIterator, class Allocator>
    unordered_flat_set(InputIterator, InputIterator, Allocator)
      -> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>,
                            boost::hash<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>,
                            std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;

  template<class InputIterator, class Hash, class Allocator>
    unordered_flat_set(InputIterator, InputIterator, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Hash,
                       Allocator)
      -> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
                            std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;

  template<class T, class Allocator>
    unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator)
      -> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;

  template<class T, class Allocator>
    unordered_flat_set(std::initializer_list<T>, Allocator)
      -> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;

  template<class T, class Hash, class Allocator>
    unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Hash, Allocator)
      -> unordered_flat_set<T, Hash, std::equal_to<T>, Allocator>;

} // namespace unordered
} // namespace boost
-----

---

=== 描述

*模板参数*

[cols="1,1"]
|===

|_Key_
|`Key` must be https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^] into the container
并且可以从容器中 https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^]。

|_Hash_
|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`.

|_Pred_
|A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type `bool`.

|_Allocator_
|An allocator whose value type is the same as the container's value type.
支持使用https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] 的分配器。

|===

容器的元素保存在内部的**桶数组**中。元素根据其哈希码被插入到对应的桶中，但如果该桶已被占用（发生**冲突**），则会使用原始位置附近的一个可用桶。

桶数组的大小可以通过调用 `insert`/`emplace` 自动增加，或者作为调用 `rehash`/`reserve` 的结果而增加。容器的**负载因子**（元素个数除以桶数量）永远不会大于 `max_load_factor()`，但在容量较小的情况下，实现可能会允许更高的负载。

如果`link:../../../../../container_hash/doc/html/hash.html#ref_hash_is_avalanching[hash_is_avalanching]<hash>::value` 为 `true`，则哈希函数将按原样使用；否则，将添加一个比特混合后处理阶段，以增加哈希质量，但会增加额外的计算成本。</hash>

---

=== 配置宏

==== `BOOST_UNORDERED_ENABLE_STATS`

全局定义此宏以启用容器的 xref:reference/stats.adoc#stats[统计信息计算]。请注意，此选项会降低许多操作的整体性能。

---

=== 类型定义

[source,c++,subs=+quotes]
----
typedef _implementation-defined_ iterator;
----

一种常量迭代器，其值类型为 `value_type`。

迭代器类别至少为前向迭代器。

可转换为 `const_iterator`。

---

[source,c++,subs=+quotes]
----
typedef _implementation-defined_ const_iterator;
----

一种常量迭代器，其值类型为 `value_type`。

迭代器类别至少为前向迭代器。

=== 构造函数

==== 默认构造函数
```c++ unordered_flat_set(); ```

使用 `hasher()` 作为哈希函数、`key_equal()` 作为键相等谓词以及 `allocator_type()` 作为分配器，构造一个空容器。

[horizontal]
后置条件：;; `size() == 0`
要求：;; 如果使用默认值，则 `hasher`、`key_equal` 和 `allocator_type` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 桶数构造函数
```c++ explicit unordered_flat_set(size_type n, const hasher&amp; hf = hasher(), const key_equal&amp; eql = key_equal(), const allocator_type&amp; a = allocator_type()); ```

构造一个至少包含 `n` 个桶的空容器，使用 `hf` 作为哈希函数，`eql` 作为键相等谓词，`a` 作为分配器。

[horizontal]
后置条件：;; `size() == 0`
要求：;; 如果使用默认值，则 `hasher`、`key_equal` 和 `allocator_type` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 迭代器范围构造函数
[source,c++,subs="+quotes"]
----
template<class InputIterator>
  unordered_flat_set(InputIterator f, InputIterator l,
                     size_type n = _implementation-defined_,
                     const hasher& hf = hasher(),
                     const key_equal& eql = key_equal(),
                     const allocator_type& a = allocator_type());
----

构造一个至少包含 `n` 个桶的空容器，使用 `hf` 作为哈希函数，`eql` 作为键相等谓词，`a` 作为分配器，并将 `[f, l)` 范围内的元素插入其中。

[horizontal]
要求：;; 如果使用默认值，则 `hasher`、`key_equal` 和 `allocator_type` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 复制构造函数
```c++ unordered_flat_set(unordered_flat_set const&amp; other); ```

复制构造函数。复制所包含的元素、哈希函数、谓词和分配器。

如果 `Allocator::select_on_container_copy_construction` 存在且具有正确的签名，则分配器将根据其结果进行构造。

[horizontal]
要求：;; `value_type` 可复制构造。

---

==== 移动构造函数
```c++ unordered_flat_set(unordered_flat_set&amp;&amp; other); ```

移动构造函数。`other` 的内部桶数组将直接转移给新容器。哈希函数、谓词和分配器从 `other` 进行移动构造。如果启用了统计信息（xref:unordered_flat_set_boost_unordered_enable_stats[enabled]），则从 `other` 转移内部统计信息，并调用 `other.reset_stats()`。

---

==== 带分配器的迭代器区间构造函数
```c++ template<class inputiterator=""> unordered_flat_set(InputIterator f, InputIterator l, const allocator_type&amp; a); ```</class>

构造一个以 `a` 为分配器的空容器，使用默认的哈希函数和键相等谓词，并将 `[f, l)` 范围内的元素插入其中。

[horizontal]
要求：;; `hasher` 和 `key_equal` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 分配器构造函数
```c++ explicit unordered_flat_set(Allocator const&amp; a); ```

构造一个空容器，使用分配器 `a`。

---

==== 带分配器的复制构造函数
```c++ unordered_flat_set(unordered_flat_set const&amp; other, Allocator const&amp; a); ```

构造一个容器，复制 `other` 所包含的元素、哈希函数和谓词，但使用分配器 `a`。

---

==== 带分配器的移动构造函数
```c++ unordered_flat_set(unordered_flat_set&amp;&amp; other, Allocator const&amp; a); ```

如果 `a == other.get_allocator()`，则 `other` 的元素会直接转移给新容器；否则，将根据 `other` 中的元素进行移动构造。哈希函数和谓词从 `other` 进行移动构造，而分配器则从 `a` 进行复制构造。如果启用了统计信息（xref:unordered_flat_set_boost_unordered_enable_stats[enabled]），则仅当 `a == other.get_allocator()` 时才从 `other` 转移内部统计信息，并且总是调用 `other.reset_stats()`。

---

==== 从 concurrent_flat_set 移动构造

```c++ unordered_flat_set(concurrent_flat_set<key, hash,="" pred,="" allocator="">&amp;&amp; other); ```</key,>

从 xref:#concurrent_flat_set[`concurrent_flat_set`] 进行移动构造。`other` 的内部桶数组将直接转移给新容器。哈希函数、谓词和分配器从 `other` 进行移动构造。如果启用了统计信息（xref:unordered_flat_set_boost_unordered_enable_stats[enabled]），则从 `other` 转移内部统计信息，并调用 `other.reset_stats()`。

[horizontal]
复杂度：;; 常数时间。
并发性：;; 在 `other` 上阻塞。

---

==== 初始化列表构造函数
[source,c++,subs="+quotes"]
----
unordered_flat_set(std::initializer_list<value_type> il,
              size_type n = _implementation-defined_
              const hasher& hf = hasher(),
              const key_equal& eql = key_equal(),
              const allocator_type& a = allocator_type());
----

构造一个至少包含 `n` 个桶的空容器，使用 `hf` 作为哈希函数，`eql` 作为键相等谓词，`a` 作为分配器，并将 `il` 中的元素插入其中。

[horizontal]
要求：;; 如果使用默认值，则 `hasher`、`key_equal` 和 `allocator_type` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 带分配器的桶数构造函数
```c++ unordered_flat_set(size_type n, allocator_type const&amp; a); ```

构造一个至少包含 `n` 个桶的空容器，使用 `hf` 作为哈希函数，默认的哈希函数和键相等谓词，并以 `a` 作为分配器。

[horizontal]
后置条件：;; `size() == 0`
要求：;; `hasher` 和 `key_equal` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 带哈希函数和分配器的桶数构造函数
```c++ unordered_flat_set(size_type n, hasher const&amp; hf, allocator_type const&amp; a); ```

构造一个至少包含 `n` 个桶的空容器，使用 `hf` 作为哈希函数，默认的键相等谓词，并以 `a` 作为分配器。

[horizontal]
后置条件：;; `size() == 0`
要求：;; `key_equal` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 带桶数和分配器的迭代器范围构造函数
[source,c++,subs="+quotes"]
----
template<class InputIterator>
  unordered_flat_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a);
----

构造一个至少包含 `n` 个桶的空容器，使用 `a` 作为分配器以及默认的哈希函数和键相等谓词，并将 `[f, l)` 范围内的元素插入其中。

[horizontal]
要求：;; `hasher` 和 `key_equal` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 带桶数和哈希函数的迭代器范围构造函数
[source,c++,subs="+quotes"]
----
    template<class InputIterator>
      unordered_flat_set(InputIterator f, InputIterator l, size_type n, const hasher& hf,
                         const allocator_type& a);
----

构造一个至少包含 `n` 个桶的空容器，使用 `hf` 作为哈希函数，`a` 作为分配器，并使用默认的键相等谓词，然后将 `[f, l)` 范围内的元素插入其中。

[horizontal]
要求：;; `key_equal` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 带分配器的初始化列表构造函数

```c++ unordered_flat_set(std::initializer_list<value_type> il, const allocator_type&amp; a); ```</value_type>

使用 `a` 以及默认的哈希函数和键相等谓词构造一个空容器，并将 `il` 中的元素插入其中。

[horizontal]
要求：;; `hasher` 和 `key_equal` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 带桶数和分配器的初始化列表构造函数

```c++ unordered_flat_set(std::initializer_list<value_type> il, size_type n, const allocator_type&amp; a); ```</value_type>

构造一个至少包含 `n` 个桶的空容器，使用 `a` 以及默认的哈希函数和键相等谓词，并将 `il` 中的元素插入其中。

[horizontal]
要求：;; `hasher` 和 `key_equal` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

==== 带桶数、哈希函数和分配器的初始化列表构造函数

```c++ unordered_flat_set(std::initializer_list<value_type> il, size_type n, const hasher&amp; hf, const allocator_type&amp; a); ```</value_type>

构造一个至少包含 `n` 个桶的空容器，使用 `hf` 作为哈希函数，`a` 作为分配器，以及默认的键相等谓词，并将 `il` 中的元素插入其中。

[horizontal]
要求：;; `key_equal` 需要是 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]。

---

=== 析构函数

```c++ ~unordered_flat_set(); ```

[horizontal]
注意：;; 析构函数会应用于每个元素，并且所有内存都会被释放。

---

=== 赋值操作

==== 复制赋值

```c++ unordered_flat_set&amp; operator=(unordered_flat_set const&amp; other); ```

赋值运算符。销毁先前存在的元素，从 `other` 复制赋值哈希函数和谓词，如果 `Alloc::propagate_on_container_copy_assignment` 存在且 `Alloc::propagate_on_container_copy_assignment::value` 为 `true`，则从 `other` 复制赋值分配器，最后插入 `other` 元素的副本。

[horizontal]
要求：;; `value_type` 必须是 https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]。

---

==== 移动赋值
```c++
unordered_flat_set&amp; operator=(unordered_flat_set&amp;&amp; other) noexcept((boost::allocator_traits<allocator>::is_always_equal::value || boost::allocator_traits<allocator>::propagate_on_container_move_assignment::value) &amp;&amp; std::is_same<pointer, value_type*="">::value);
```
移动赋值运算符。销毁先前存在的元素，交换来自 `other` 的哈希函数和谓词，如果 `Alloc::propagate_on_container_move_assignment` 存在且 `Alloc::propagate_on_container_move_assignment::value` 为 `true`，则从 `other` 移动赋值分配器。如果此时分配器等于 `other.get_allocator()`，则 `other` 的内部桶数组直接转移给当前容器；否则，插入 `other` 元素的移动构造副本。如果启用了统计信息（xref:unordered_flat_set_boost_unordered_enable_stats[enabled]），则仅当最终的分配器等于 `other.get_allocator()` 时才从 `other` 转移内部统计信息，并且总是调用 `other.reset_stats()`。</pointer,></allocator></allocator>

---

==== 初始化列表赋值
```c++ unordered_flat_set&amp; operator=(std::initializer_list<value_type> il); ```</value_type>

从初始化列表中的值进行赋值。所有先前存在的元素均被销毁。

[horizontal]
要求：;; `value_type` 必须是 https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]。

=== 迭代器

==== begin
```c++ iterator begin() noexcept; const_iterator begin() const noexcept; ```

[horizontal]
返回：;; 指向容器第一个元素的迭代器，若容器为空，则返回容器的尾后迭代器。
复杂度：;; O(`bucket_count()`)

---

==== end
```c++ iterator end() noexcept; const_iterator end() const noexcept; ```

[horizontal]
返回：;; 指向容器尾后值的迭代器。

---

==== cbegin
```c++ const_iterator cbegin() const noexcept; ```

[horizontal]
返回：;; 指向容器第一个元素的常量迭代器，若容器为空，则返回容器的尾后常量迭代器。
复杂度：;; O(`bucket_count()`)

---

==== cend
```c++ const_iterator cend() const noexcept; ```

[horizontal]
返回：;; 指向容器尾后值的常量迭代器。

---

=== 大小与容量

==== 空

```c++ [[nodiscard]] bool empty() const noexcept; ```

[horizontal]
返回：;; `size() == 0`

---

==== 大小

```c++ size_type size() const noexcept; ```

[horizontal]
返回：;; `std::distance(begin(), end())`

---

==== max_size

```c++ size_type max_size() const noexcept; ```

[horizontal]
返回：;; 可能的最大容器的 `size()`。

---

=== 修改器

==== 原地构造
```c++ template<class... args=""> std::pair<iterator, bool=""> emplace(Args&amp;&amp;... args); ```</iterator,></class...>

当且仅当容器中不存在具有等价键的元素时，才插入一个使用参数 `args` 构造的对象。

[horizontal]
要求：;; `value_type` 可以从 `args` 构造。
返回：;; 如果进行了插入，则返回类型的 `bool` 分量为 `true`。
如果进行了插入，则迭代器指向新插入的元素；否则，指向具有等价键的元素。
抛出：;; 如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。
备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载因子大于最大负载因子时才会发生。

---

==== emplace_hint
```c++ template<class... args=""> iterator emplace_hint(const_iterator position, Args&amp;&amp;... args); ```</class...>

当且仅当容器中不存在具有等价键的元素时，才插入一个使用参数 `args` 构造的对象。

`position` 是关于元素应该插入位置的一个提示。此实现会忽略它。

[horizontal]
要求：;; `value_type` 可以从 `args` 构造。
返回：;; 如果进行了插入，则返回类型的 `bool` 分量为 `true`。
如果进行了插入，则迭代器指向新插入的元素；否则，指向具有等价键的元素。
抛出：;; 如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。
备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载因子大于最大负载因子时才会发生。

---

==== 复制插入
```c++ std::pair<iterator, bool=""> insert(const value_type&amp; obj); ```</iterator,>

当且仅当容器中不存在具有等价键的元素时，才将 `obj` 插入容器中。

[horizontal]
要求：;; `value_type` 必须是 https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]。
返回：;; 如果进行了插入，则返回类型的 `bool` 分量为 `true`。
如果进行了插入，则迭代器指向新插入的元素；否则，指向具有等价键的元素。
抛出：;; 如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。
备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载大于最大负载时才会发生。

---

==== 移动插入
```c++ std::pair<iterator, bool=""> insert(value_type&amp;&amp; obj); ```</iterator,>

当且仅当容器中不存在具有等价键的元素时，才将 `obj` 插入容器中。

[horizontal]
要求：;; `value_type` 必须是 https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]。
返回：;; 如果进行了插入，则返回类型的 `bool` 分量为 `true`。
如果进行了插入，则迭代器指向新插入的元素；否则，指向具有等价键的元素。
抛出：;; 如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。
备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载大于最大负载时才会发生。

---

==== 透明插入
```c++ template<class k=""> std::pair<iterator, bool=""> insert(K&amp;&amp; k); ```</iterator,></class>

当且仅当容器中不存在具有等价键的元素时，才插入一个从 `std::forward<k>(k)` 构造的元素。</k>

[horizontal]
要求：;; `value_type` 可以从 `k` 进行 https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^]。
返回：;; 如果进行了插入，则返回类型的 bool 分量为 true。
如果进行了插入，则迭代器指向新插入的元素；否则，指向具有等价键的元素。
抛出：;; 如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。
备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载大于最大负载时才会发生。
此外，仅当 `Hash::is_transparent` 和 `Pred::is_transparent` 是有效的成员 typedef，并且 `K` 不能隐式转换为 `iterator` 或 `const_iterator` 时，此重载才会参与重载决议。库假定 `Hash` 可同时以 `K` 和 `Key` 类型调用，且 `Pred` 是透明的。这支持了异构查找，从而避免了实例化 `Key` 类型的开销。

---

==== 带提示的复制插入
```c++iterator insert(const_iterator hint, const value_type&amp; obj);
```当且仅当容器中不存在具有等价键的元素时，才将 `obj` 插入容器中。

`hint` 是关于元素应该插入位置的一个提示。此实现会忽略它。

[horizontal]
要求：;; `value_type` 必须是 https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]。
返回：;; 如果进行了插入，则返回类型的 `bool` 分量为 `true`。
如果进行了插入，则迭代器指向新插入的元素；否则，指向具有等价键的元素。
抛出：;; 如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。
备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载大于最大负载时才会发生。

---

==== 带提示的移动插入
```c++ iterator insert(const_iterator hint, value_type&amp;&amp; obj); ```

当且仅当容器中不存在具有等价键的元素时，才将 `obj` 插入容器中。

`hint` 是关于元素应该插入位置的一个提示。此实现会忽略它。

[horizontal]
要求：;; `value_type` 必须是 https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]。
返回：;; 如果进行了插入，则返回类型的 `bool` 分量为 `true`。
如果进行了插入，则迭代器指向新插入的元素；否则，指向具有等价键的元素。
抛出：;; 如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。
备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载大于最大负载时才会发生。

---

==== 带提示的透明插入
```c++ template<class k=""> std::pair<iterator, bool=""> insert(const_iterator hint, K&amp;&amp; k); ```</iterator,></class>

当且仅当容器中不存在具有等价键的元素时，才插入一个从 `std::forward<k>(k)` 构造的元素。</k>

`hint` 是关于元素应该插入位置的一个提示。此实现会忽略它。

[horizontal]
要求：;; `value_type` 可以从 `k` 进行 https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^]。
返回：;; 如果进行了插入，则返回类型的 bool 分量为 true。
如果进行了插入，则迭代器指向新插入的元素；否则，指向具有等价键的元素。
抛出：;; 如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。
备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载大于最大负载时才会发生。
此外，仅当 `Hash::is_transparent` 和 `Pred::is_transparent` 是有效的成员 typedef，并且 `K` 不能隐式转换为 `iterator` 或 `const_iterator` 时，此重载才会参与重载决议。库假定 `Hash` 可同时以 `K` 和 `Key` 类型调用，且 `Pred` 是透明的。这支持了异构查找，从而避免了实例化 `Key` 类型的开销。

---

==== 迭代器范围插入
```c++ template<class inputiterator=""> void insert(InputIterator first, InputIterator last); ```</class>

将一系列元素插入容器中。当且仅当容器中不存在具有等价键的元素时，才插入该元素。

[horizontal]
要求：;; `value_type` 可以从 `*first` 进行 https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] 到容器中。
抛出：;; 当插入单个元素时，如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。
备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载大于最大负载时才会发生。

---

==== 初始化列表插入
```c++ void insert(std::initializer_list<value_type>); ```</value_type>

将一系列元素插入容器中。当且仅当容器中不存在具有等价键的元素时，才插入该元素。

[horizontal]
要求：;; `value_type` 必须可以 https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] 到容器中。抛出：;; 当插入单个元素时，如果除调用 `hasher` 之外的操作抛出异常，则该函数无效。备注：;; 可能会使迭代器、指针和引用失效，但仅当插入导致负载大于最大负载时才会发生。

---

==== 通过位置擦除

[source,c++,subs=+quotes]
----
_convertible-to-iterator_ erase(iterator position);
_convertible-to-iterator_ erase(const_iterator position);
----

擦除由 `position` 指向的元素。

[horizontal]
返回：;; 一个不透明对象，可隐式转换为擦除前紧接 `position` 之后的 `iterator` 或 `const_iterator`。抛出：;; 无。备注：;; 返回的不透明对象只能被丢弃或立即转换为 `iterator` 或 `const_iterator`。

---

==== 通过键擦除
```c++ size_type erase(const key_type&amp; k); template<class k=""> size_type erase(K&amp;&amp; k); ```</class>

删除所有键与 `k` 等价的元素。

[horizontal]
返回：;; 被删除的元素数量。抛出：;; 仅当由 `hasher` 或 `key_equal` 抛出异常时才会抛出异常。备注：;; `template<class k="">` 重载仅当 `Hash::is_transparent` 和 `Pred::is_transparent` 是有效的成员 typedef，并且 `K` 不能隐式转换为 `iterator` 或 `const_iterator` 时，才会参与重载决议。库假定 `Hash` 可同时以 `K` 和 `Key` 类型调用，且 `Pred` 是透明的。这支持了异构查找，从而避免了实例化 `Key` 类型的开销。</class>

---

==== 范围擦除

```c++ iterator erase(const_iterator first, const_iterator last); ```

删除从 `first` 到 `last` 范围内的元素。

[horizontal]
返回：;; 被删除元素之后的迭代器，即 `last`。抛出：;; 在此实现中不抛出任何异常（既不会调用 `hasher` 也不会调用 `key_equal` 对象）。

---

==== 交换
```c++ void swap(unordered_flat_set&amp; other) noexcept(boost::allocator_traits<allocator>::is_always_equal::value || boost::allocator_traits<allocator>::propagate_on_container_swap::value); ```</allocator></allocator>

交换容器与参数的内容。

如果 `Allocator::propagate_on_container_swap` 已声明且 `Allocator::propagate_on_container_swap::value` 为 `true`，则交换两个容器的分配器。否则，使用不相等的分配器进行交换将导致未定义行为。

[horizontal]
抛出：;; 除非 `key_equal` 或 `hasher` 在交换时抛出异常，否则不抛出任何异常。

---

==== pull
```c++ init_type pull(const_iterator position); ```

从 `position` 指向的元素移动构造一个 `init_value` `x`，删除该元素并返回 `x`。

---

==== 清空
```c++ void clear() noexcept; ```

清除容器中的所有元素。

[horizontal]
Postconditions:;; `size() == 0`, `max_load() &gt;= max_load_factor() * bucket_count()`

---

==== 合并
```c++ template<class h2,="" class="" p2=""> void merge(unordered_flat_set<key, t,="" h2,="" p2,="" allocator="">&amp; source); template<class h2,="" class="" p2=""> void merge(unordered_flat_set<key, t,="" h2,="" p2,="" allocator="">&amp;&amp; source); ```</key,></class></key,></class>

移动插入 `source` 中所有键尚未存在于 `*this` 中的元素，并从 `source` 中删除它们。

---

=== 观察器

==== get_allocator
``` allocator_type get_allocator() const noexcept; ```

[horizontal]
返回：;; 容器的分配器。

---

==== 哈希函数
``` hasher hash_function() const; ```

[horizontal]
返回：;; 容器的哈希函数。

---

==== key_eq
``` key_equal key_eq() const; ```

[horizontal]
返回：;; 容器的键相等谓词。

---

=== 查找

==== find
```c++ iterator         find(const key_type&amp; k); const_iterator   find(const key_type&amp; k) const; template<class k=""> iterator       find(const K&amp; k);</class>

```

[horizontal]
返回：;; 指向键与 `k` 等价之元素的迭代器，若无此元素则返回 `end()`。备注：;; `template<class k="">` 重载仅当 `Hash::is_transparent` 和 `Pred::is_transparent` 是有效的成员 typedef 时才会参与重载决议。库假定 `Hash` 可同时以 `K` 和 `Key` 类型调用，且 `Pred` 是透明的。这支持了异构查找，从而避免了实例化 `Key` 类型的开销。</class>

---

==== count
```c++ size_type        count(const key_type&amp; k) const; template<class k=""> size_type      count(const K&amp; k) const; ```</class>

[horizontal]
返回：;; 键与 `k` 等价的元素个数。备注：;; `template<class k="">` 重载仅当 `Hash::is_transparent` 和 `Pred::is_transparent` 是有效的成员 typedef 时才会参与重载决议。库假定 `Hash` 可同时以 `K` 和 `Key` 类型调用，且 `Pred` 是透明的。这支持了异构查找，从而避免了实例化 `Key` 类型的开销。</class>

---

==== 包含
```c++ bool             contains(const key_type&amp; k) const; template<class k=""> bool           contains(const K&amp; k) const; ```</class>

[horizontal]
返回：;; 一个布尔值，指示容器中是否存在键等于 `key` 的元素。备注：;; `template<class k="">` 重载仅当 `Hash::is_transparent` 和 `Pred::is_transparent` 是有效的成员 typedef 时才会参与重载决议。库假定 `Hash` 可同时以 `K` 和 `Key` 类型调用，且 `Pred` 是透明的。这支持了异构查找，从而避免了实例化 `Key` 类型的开销。</class>

---

==== equal_range
```c++ std::pair<iterator, iterator="">               equal_range(const key_type&amp; k); std::pair<const_iterator, const_iterator="">   equal_range(const key_type&amp; k) const; template<class k=""> std::pair<iterator, iterator="">             equal_range(const K&amp; k); template<class k=""> std::pair<const_iterator, const_iterator=""> equal_range(const K&amp; k) const; ```</const_iterator,></class></iterator,></class></const_iterator,></iterator,>

[horizontal]
返回：;; 一个范围，包含所有键与 `k` 等价的元素。若容器中不包含任何此类元素，则返回 `std::make_pair(b.end(), b.end())`。备注：;; `template<class k="">` 重载仅当 `Hash::is_transparent` 和 `Pred::is_transparent` 是有效的成员 typedef 时才会参与重载决议。库假定 `Hash` 可同时以 `K` 和 `Key` 类型调用，且 `Pred` 是透明的。这支持了异构查找，从而避免了实例化 `Key` 类型的开销。</class>

---

=== 桶接口

==== bucket_count
```c++ size_type bucket_count() const noexcept; ```

[horizontal]
返回：;; 桶数组的大小。

---

=== 哈希策略

==== 负载因子
```c++ float load_factor() const noexcept; ```

[horizontal]
返回：;; `static_cast<float>(size())/static_cast<float>(bucket_count())`，如果 `bucket_count() == 0` 则返回 `0`。</float></float>

---

==== 最大负载因子

```c++ float max_load_factor() const noexcept; ```

[horizontal]
返回：;; 返回容器的最大负载因子。

---

==== 设置最大负载因子
```c++ void max_load_factor(float z); ```

[horizontal]
效果：;; 不执行任何操作，因为用户不允许更改此参数。为与 `boost::unordered_set` 保持兼容而保留。

---


==== 最大负载

```c++ size_type max_load() const noexcept; ```

[horizontal]
返回：;; 假设不再删除更多元素，容器在不进行重哈希的情况下所能容纳的最大元素数量。注意：;; 在构造、重哈希或清空之后，容器的最大负载至少为 `max_load_factor() * bucket_count()`。在高负载条件下，该值可能因删除操作而减小。

---

==== 重哈希
```c++ void rehash(size_type n); ```

必要时改变桶数组的大小，使得至少包含 `n` 个桶，并且负载因子小于或等于最大负载因子。在适用的情况下，这将增大或缩小与容器相关联的 `bucket_count()`。

当 `size() == 0` 时，`rehash(0)` 将释放底层桶数组的内存。如果所提供的分配器使用 fancy pointers，随后将执行一次默认分配。

使迭代器、指针和引用失效，并改变元素的顺序。

[horizontal]
抛出：;; 如果抛出异常（除非是由容器的哈希函数或比较函数抛出），则该函数无效。

---

==== 保留
```c++ void reserve(size_type n); ```

等价于 `a.rehash(ceil(n / a.max_load_factor()))`。

与 `rehash` 类似，此函数可用于增加或减少容器中桶的数量。

使迭代器、指针和引用失效，并改变元素的顺序。

[horizontal]
抛出：;; 如果抛出异常（除非是由容器的哈希函数或比较函数抛出），则该函数无效。

---

=== 统计信息

==== get_stats
```c++ stats get_stats() const; ```

[horizontal]
返回：;; 对容器迄今为止所执行的插入和查找操作的统计描述。备注：;; 仅在 xref:reference/stats.adoc#stats[统计信息计算] 已 xref:unordered_flat_set_boost_unordered_enable_stats[启用] 时可用。

---

==== reset_stats
```c++ void reset_stats() noexcept; ```

[horizontal]
效果：;; 将容器内部保持的统计信息归零。备注：;; 仅在 xref:reference/stats.adoc#stats[统计信息计算] 已 xref:unordered_flat_set_boost_unordered_enable_stats[启用] 时可用。

---

=== 推导指引
在以下任一条件成立时，推导指引将不参与重载决议：

- 它具有 `InputIterator` 模板参数，并且为该参数推导出的类型不符合输入迭代器的要求。- 它具有 `Allocator` 模板参数，并且为该参数推导出的类型不符合分配器的要求。- 它具有 `Hash` 模板参数，并且为该参数推导出的是整数类型或符合分配器要求的类型。- 它具有 `Pred` 模板参数，并且为该参数推导出的是符合分配器要求的类型。

推导指引中的 `size_type` 参数类型指向由该推导指引所推导出的容器类型的 `size_type` 成员类型。其默认值与所选构造函数的默认值一致。

==== _iter-value-type_
[listings,subs="+macros,+quotes"]
-----
template<class InputIterator>
  using __iter-value-type__ =
    typename std::iterator_traits<InputIterator>::value_type; // exposition only
-----

=== 相等性比较

==== operator
```c++ template<class key,="" class="" t,="" hash,="" pred,="" alloc=""> bool operator==(const unordered_flat_set<key, t,="" hash,="" pred,="" alloc="">&amp; x, const unordered_flat_set<key, t,="" hash,="" pred,="" alloc="">&amp; y); ```</key,></key,></class>

如果 `x.size() == y.size()` 并且对于 `x` 中的每个元素，在 `y` 中都有一个具有相同键且值相等的元素（使用 `operator==` 比较值类型），则返回 `true`。

[horizontal]
备注：;; 如果两个容器不具有等价的相等谓词，则行为未定义。

---

==== operator!
```c++ template<class key,="" class="" t,="" hash,="" pred,="" alloc=""> bool operator!=(const unordered_flat_set<key, t,="" hash,="" pred,="" alloc="">&amp; x, const unordered_flat_set<key, t,="" hash,="" pred,="" alloc="">&amp; y); ```</key,></key,></class>

如果 `x.size() == y.size()` 并且对于 `x` 中的每个元素，在 `y` 中都有一个具有相同键且值相等的元素（使用 `operator==` 比较值类型），则返回 `false`。

[horizontal]
备注：;; 如果两个容器不具有等价的相等谓词，则行为未定义。

=== 交换
```c++ template<class key,="" class="" t,="" hash,="" pred,="" alloc=""> void swap(unordered_flat_set<key, t,="" hash,="" pred,="" alloc="">&amp; x, unordered_flat_set<key, t,="" hash,="" pred,="" alloc="">&amp; y) noexcept(noexcept(x.swap(y))); ```</key,></key,></class>

交换 `x` 和 `y` 的内容。

如果 `Allocator::propagate_on_container_swap` 已声明且 `Allocator::propagate_on_container_swap::value` 为 `true`，则交换两个容器的分配器。否则，使用不相等的分配器进行交换将导致未定义行为。

[horizontal]
效果：;; `x.swap(y)` 抛出：;; 除非 `key_equal` 或 `hasher` 在交换时抛出异常，否则不抛出任何异常。

---

=== erase_if
```c++ template<class k,="" class="" t,="" h,="" p,="" a,="" predicate=""> typename unordered_flat_set<k, t,="" h,="" p,="" a="">::size_type erase_if(unordered_flat_set<k, t,="" h,="" p,="" a="">&amp; c, Predicate pred); ```</k,></k,></class>

遍历容器 `c` 并移除所有使给定谓词返回 `true` 的元素。

[horizontal]
返回：;; 被移除的元素数量。备注：;; 等价于：```c++ auto original_size = c.size(); for (auto i = c.begin(), last = c.end(); i != last; ) { if (pred(*i)) { i = c.erase(i); } else { ++i; } } return original_size - c.size(); ```

=== 序列化

`unordered_flat_set` 可以通过本库提供的 API，使用 link:../../../../../serialization/index.html[Boost.Serialization^] 进行归档/恢复。支持常规归档和 XML 归档。

==== 将 unordered_flat_set 保存到归档中

将 `unordered_flat_set` `x` 的所有元素保存到归档（XML 归档）`ar` 中。

[horizontal]
要求：;; `value_type` 必须是可序列化的（支持 XML 序列化），并且支持 Boost.Serialization 的 `save_construct_data`/`load_construct_data` 协议（该协议由 https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] 类型的自动支持）。

---

==== 从归档中加载 unordered_flat_set

删除 `unordered_flat_set` `x` 中所有已存在的元素，并从归档（XML 归档）`ar` 中插入由 `ar` 所读取存储中保存的原始 `unordered_flat_set` `other` 元素的恢复副本。

[horizontal]
要求：;; `x.key_equal()` 在功能上等价于 `other.key_equal()`。

---

==== 将迭代器/常量迭代器保存到归档

将 `iterator`（`const_iterator`）`it` 的位置信息保存到归档（XML 归档）`ar` 中。`it` 可以是 `end()` 迭代器。

[horizontal]
要求：;; `it` 所指向的 `unordered_flat_set` `x` 此前已保存至 `ar`，并且在保存 `x` 和保存 `it` 之间未对 `x` 执行任何修改操作。

---

==== 从归档加载迭代器/常量迭代器

使 `iterator`（`const_iterator`）`it` 指向保存到由归档（XML 归档）`ar` 读取的存储中的原始 `iterator`（`const_iterator`）的被恢复位置。

[horizontal]
要求：;; 如果 `x` 是 `it` 所指向的 `unordered_flat_set`，则在加载 `x` 和加载 `it` 之间未对 `x` 执行任何修改操作。
