Use of string_view for map lookup

The following code fails to build on recent compilers (g++-5.3, clang++-3.7).

#include <map>
#include <functional>
#include <experimental/string_view>

void f()
{
    using namespace std;
    using namespace std::experimental;
    map<string, int> m;
    string s = "foo";
    string_view sv(s);
    m.find(sv);
}

Error returned by clang :

error: no matching member function for call to 'find'
    m.find(sv);
    ~~^~~~

But shouldn't find be able to use comparable types ? Cppreference mentions the following overload :

template< class K > iterator find( const K& x );

The same error happens with boost::string_ref.


You need to specify a transparent comparator explicitly (like std::less<>):

std::map<std::string, int, std::less<>> m;
//                         ~~~~~~~~~~^

std::map<K,V> defaults its comparator to std::less<K> (i.e., a non-transparent one), and since ([associative.reqmts]/p13):

The member function templates find, count, lower_bound, upper_bound, and equal_range shall not participate in overload resolution unless the qualified-id Compare::is_transparent is valid and denotes a type (14.8.2).

the template member function find is not a viable candidate.

Heterogeneous comparison lookup for associative containers was added to c++14. The original proposal risked breaking existing code. For example:

c.find(x);

is semantically equivalent to:

key_type key = x;
c.find(key);

In particular, the conversion between x and key_type happens only once, and before the actual call.

Heterogenous lookup replaces this conversion in favour of a comparison between key and x. This may lead to a drop in performance in existing code (due to addtional conversion before each comparison) or even break compilation (if the comparison operator is a member function, it will not apply conversion for a left-hand side operand):

#include <set>
#include <functional>

struct A
{
    int i;

    A(int i) : i(i) {}
};

bool operator<(const A& lhs, const A& rhs)
{
    return lhs.i < rhs.i;
}

int main()
{
    std::set<A, std::less<>> s{{1}, {2}, {3}, {4}};
    s.find(5);
}

DEMO

To resolve this the new behaviour was made opt-in by adding the concept of transparent comparators as described in the linked question.