Search code examples
c++stlc++17c++14standards

Why does `std::set::extract` not support heterogeneous lookup as `std::set::find`?


#include <set>
#include <string>
#include <string_view>

using namespace std::literals;

int main()
{
    auto coll = std::set<std::string, std::less<>>{"abc"s, "xyz"s};
    coll.find("abc"sv);    // ok
    coll.extract("abc"sv); // error
}

See online demo

Why does std::set::extract not support heterogeneous lookup as std::set::find?


Solution

  • The overloading of std::set::extract() in C++17 standard is as follows:

    node_type extract(const_iterator position);  // (1)
    node_type extract(const key_type& x);        // (2)
    

    Assume that the following overload exist here (it does not exist in C++17 standard):

    template<typename K>
    node_type extract(const K& x);               // (3)
    

    When an iterator object is passed to extract(), you would expect it to be implicitly converted to a const_iterator and (1) would be called, but in fact (3) would be selected.

    This can be avoided by adding the following overload (not in the C++17 standard):

    node_type extract(iterator position);        // (4)
    

    However, even in this case, if you pass an object that implicitly convertible to iterator or const_iterator, (3) will be called. This may not be what you expect.


    P2077R2 proposes to introduce the following overloads with constraints.

    template<typename K>
    node_type extract(K&& x);                    // (5)
    

    Constraint: in addition to the presence of Compare::is_transparent, this overload will not be selected if K&& is implicitly convertible to iterator or const_iterator.