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.

3227. Ambiguity issue for extract in ordered and unordered associative containers

Section: 22.2.6 [associative.reqmts], 22.2.7 [unord.req] Status: New Submitter: Konstantin Boyarinov Opened: 2019-06-25 Last modified: 2020-09-06

Priority: 3

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with New status.

Discussion:

Ordered and unordered associative containers in C++14 contained an issue, which caused an ambiguity while invoking std::map::erase when key_type of the map can be constructed from the iterator. In this case both overloads erase(const key_type&) and erase(const_iterator) could be chosen.

The issue LWG 2059 was reported and resolved in C++17 by adding an extra overload for erase in ordered and unordered associative containers which accepts iterator as an argument.

C++17 also introduced new functionality for splicing ordered and unordered maps and sets. One of the extensions allows to extract a node from the container by passing either key_type& or const_iterator to the extract() member function:

node_type extract(const key_type& x);
node_type extract(const_iterator position);

Providing these two extract overloads causes the same problem as for erase. Consider the following example:

#include <map>
#include <string>

struct Key
{
  template <typename T>
  Key(const T&) {}
};

bool operator<(const Key&, const Key&) { return false; }

int main()
{
  using map_type = std::map<Key, std::string>;

  map_type m({ {Key(1), "a"}, {Key(2), "b"} });
  map_type::iterator it = m.begin();
  auto nh = m.extract(it);
}

In this case, call to extract() is ambiguous, because the overloads which accept const_iterator and key_type are equally good matches for the argument it.

Consequently, this issue can be resolved in the same way as for std::map::erase by adding an overload for extract which accepts iterator as an argument.

[2019-07 Issue Prioritization]

Priority to 3 after discussion on the reflector.

Proposed resolution:

This wording is relative to N4820.

  1. Modify [tab:container.assoc.req], Table 69 — "Associative container requirements", as indicated:

    Table 69 — Associative container requirements (in addition to container) [tab:container.assoc.req]
    Expression Return type Assertion/note pre-/post-condition Complexity
    a.extract(q) node_type Effects: Removes the element
    pointed to by q.
    Returns: A node_type owning
    that element.
    amortized constant
    a.extract(r) node_type Effects: Removes the element
    pointed to by r.
    Returns: A node_type owning
    that element.
    amortized constant
  2. Modify [tab:container.assoc.req], Table 70 — "Unordered associative container requirements", as indicated:

    Table 70 — Unordered associative container requirements (in addition to container) [tab:container.hash.req]
    Expression Return type Assertion/note pre-/post-condition Complexity
    a.extract(q) node_type Effects: Removes the element
    pointed to by q.
    Returns: A node_type owning
    that element.
    Average case 𝒪(1), worst case 𝒪(a.size()).
    a.extract(r) node_type Effects: Removes the element
    pointed to by r.
    Returns: A node_type owning
    that element.
    Average case 𝒪(1), worst case 𝒪(a.size()).
  3. Modify 22.4.4.1 [map.overview], class template map synopsis, as indicated:

    […]
    node_type extract(iterator position);
    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    […]
    
  4. Modify 22.4.5.1 [multimap.overview], class template multimap synopsis, as indicated:

    […]
    node_type extract(iterator position);
    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    […]
    
  5. Modify 22.4.6.1 [set.overview], class template set synopsis, as indicated:

    […]
    node_type extract(iterator position);
    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    […]
    
  6. Modify 22.4.7.1 [multiset.overview], class template multiset synopsis, as indicated:

    […]
    node_type extract(iterator position);
    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    […]
    
  7. Modify 22.5.4.1 [unord.map.overview], class template unordered_map synopsis, as indicated:

    […]
    node_type extract(iterator position);
    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    […]
    
  8. Modify 22.5.5.1 [unord.multimap.overview], class template unordered_multimap synopsis, as indicated:

    […]
    node_type extract(iterator position);
    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    […]
    
  9. Modify 22.5.6.1 [unord.set.overview], class template unordered_set synopsis, as indicated:

    […]
    node_type extract(iterator position);
    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    […]
    
  10. Modify 22.5.7.1 [unord.multiset.overview], class template unordered_multiset synopsis, as indicated:

    […]
    node_type extract(iterator position);
    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    […]