This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4180. Inconsistent constraints on flat_foo::emplace

Section: 23.6.12.5 [flat.multiset.modifiers], 23.6.8.7 [flat.map.modifiers] Status: New Submitter: Arthur O'Dwyer Opened: 2024-12-09 Last modified: 2024-12-14

Priority: Not Prioritized

View all issues with New status.

Discussion:

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

Constraints on emplace: flat_map (23.6.8.7 [flat.map.modifiers] p1), flat_multiset (23.6.12.5 [flat.multiset.modifiers] p1), any (22.7.4.4 [any.modifiers] p1), expected (22.8.6.4 [expected.object.assign] p16), variant (22.6.3.5 [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.

Proposed resolution:

This wording is relative to N4993.

[Drafting note: 23.6.11.5 [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 23.6.12.5 [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 23.6.8.7 [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.