diff --git a/xml/issue4180.xml b/xml/issue4180.xml new file mode 100644 index 0000000000..b6cff242ea --- /dev/null +++ b/xml/issue4180.xml @@ -0,0 +1,106 @@ + + + + +Inconsistent constraints on <tt>flat_<i>foo</i>::emplace</tt> +
+Arthur O'Dwyer +09 Dec 2024 +99 + + +

+The usual pattern in is that `x.emplace(args...)` has a precondition +( p20, p48) but no +Constraints element. That is, `emplace` is not SFINAE-friendly. And it has only the one overload, +so it doesn't need a constraint for purposes of overload resolution. +

+No Constraints on `emplace`: `deque`, `list`, `vector`, `containers`, `associative containers`, `unordered containers`, +`priority_queue`, `optional`. +

+Constraints on `emplace`: `flat_map`, `flat_multiset`, `any`, `expected`, `variant`. +

+I believe a Constraints element was accidentally copy-pasted from the spec of flat_map::insert(P&&) + — which does need the constraint because it's part of `insert`'s large overload set — to + `flat_map::emplace`, and then from there to `flat_multiset::emplace`. The constraint is already (correctly) absent + `from flat_set::emplace`. +

+While we're touching this paragraph, also resolve the vague word "initializes" to "direct-non-list-initializes." +Editorially, pair<…> is a verbose way to spell the `value_type` of a `flat_map`; we should +be consistent and just say `value_type`. +

+
+ + +

+This wording is relative to . +

+ +
+

+[Drafting note: is already OK as far as this issue is concerned: +it has no wording for `emplace`. +

+[flat.multimap.modifiers] is already OK ditto: it does not exist. ] +

+
+ +
    +
  1. Modify as indicated:

    + +
    +
    +template<class... Args> iterator emplace(Args&&... args);
    +
    +
    +

    +-1- MandatesConstraints: is_constructible_v<value_type, Args...> is true. +

    +-2- Effects: First, direct-non-list-initializes an object `t` of type `value_type` with +std::forward<Args>(args)..., then inserts `t` as if by: +

    +
    +auto it = ranges::upper_bound(c, t, compare);
    +c.insert(it, std::move(t));
    +
    +

    +-3- Returns: An iterator that points to the inserted element. +

    +
    +
    + +
  2. + +
  3. Modify as indicated:

    + +
    +
    +template<class... Args> pair<iterator, bool> emplace(Args&&... args);
    +
    +
    +

    +-1- MandatesConstraints: is_constructible_v<value_typepair<key_type, mapped_type>, Args...> +is true. +

    +-2- Effects: First, direct-non-list-iInitializes an object `t` of type +value_typepair<key_type, mapped_type> with std::forward<Args>(args)...; +if the map already contains an element whose key is equivalent to `t.first`, `*this` is unchanged. Otherwise, equivalent to: +

    +
    +auto key_it = ranges::upper_bound(c.keys, t.first, compare);
    +auto value_it = c.values.begin() + distance(c.keys.begin(), key_it);
    +c.keys.insert(key_it, std::move(t.first));
    +c.values.insert(value_it, std::move(t.second));
    +
    +

    +-3- Returns: The `bool` component of the returned pair is `true` if and only if the insertion took place, and +the iterator component of the pair points to the element with key equivalent to `t.first`. +

    +
    +
    + +
  4. +
+
+ +