Использование string_view для поиска карты

Следующий код не может быть создан на последних компиляторах (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);
}

Ошибка, возвращаемая clang:

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

Но не следует ли find использовать сопоставимые типы? В Cppreference упоминается следующая перегрузка:

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

То же самое происходит с boost::string_ref.

Ответ 1

Вам нужно явно указать прозрачный компаратор (например, std::less<>):

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

std::map<K,V> умолчанию использует свой компаратор: std::less<K> (т.е. непрозрачный), и так как ([associative.reqmts]/p13):

Шаблоны функций-членов find, count, lower_bound, upper_bound и equal_range не должны участвовать в разрешении перегрузки, если квалифицированный идентификатор Compare::is_transparent является допустимым и не обозначает тип (14.8.2).

функция-член шаблона find не является подходящим кандидатом.

Гетерогенный сравнительный поиск для ассоциативных контейнеров был добавлен в . Первоначальное предложение рисковало нарушить существующий код. Например:

c.find(x);

семантически эквивалентно:

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

В частности, преобразование между x и key_type происходит только один раз и перед фактическим вызовом.

Гетерогенный поиск заменяет это преобразование в пользу сравнения между key и x. Это может привести к снижению производительности в существующем коде (из-за дополнительного преобразования перед каждым сравнением) или даже к прерыванию компиляции (если оператор сравнения является функцией-членом, он не будет применять преобразование для левого операнда):

#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

Для решения этой проблемы было добавлено новое поведение путем добавления концепции прозрачных компараторов, как описано в связанном вопросе.