Title
Inconsistent constraints on flat_foo::emplace
Status
new
Section
[flat.multiset.modifiers][flat.map.modifiers]
Submitter
Arthur O'Dwyer

Created on 2024-12-09.00:00:00 last changed 7 days ago

Messages

Date: 2024-12-14.15:46:49

Proposed resolution:

This wording is relative to N4993.

[Drafting note: [flat.set.modifiers] 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 [flat.multiset.modifiers] 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. Modify [flat.map.modifiers] 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`.

Date: 2024-12-09.00:00:00

The usual pattern in [containers] is that `x.emplace(args...)` has a precondition ([sequence.reqmts] p20, [associative.reqmts.general] 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` ([deque.modifiers]), `list` ([list.modifiers]), `vector` ([vector.modifiers]), `containers` ([sequence.reqmts] p19), `associative containers` ([associative.reqmts.general] p47), `unordered containers` ([unord.req.general] p78), `priority_queue` ([priqueue.members] p5), `optional` ([optional.assign] p29).

Constraints on `emplace`: `flat_map` ([flat.map.modifiers] p1), `flat_multiset` ([flat.multiset.modifiers] p1), `any` ([any.modifiers] p1), `expected` ([expected.object.assign] p16), `variant` ([variant.mod] p1).

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`.

History
Date User Action Args
2024-12-14 15:46:49adminsetmessages: + msg14520
2024-12-09 00:00:00admincreate