Что такое прозрачные компараторы?
в C++14 ассоциативные контейнеры, похоже, изменились с C++11 – [ассоциативный.reqmts] / 13 говорит:
шаблоны функций-членов
find,count,lower_bound,upper_boundиequal_rangeне участвует в разрешении перегрузки, если тип .
какова цель сделать компаратор "прозрачным"?
C++14 также предоставляет шаблоны библиотек, как это:
template <class T = void> struct less {
constexpr bool operator()(const T& x, const T& y) const;
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
};
template <> struct less<void> {
template <class T, class U> auto operator()(T&& t, U&& u) const
-> decltype(std::forward<T>(t) < std::forward<U>(u));
typedef *unspecified* is_transparent;
};
так для например, std::set<T, std::less<T>> б не есть прозрачный компаратор, но std::set<T, std::less<>>б есть один.
какую проблему это решает, и это меняет, как работают стандартные контейнеры? Например, параметры шаблона std::set по-прежнему Key, Compare = std::less<Key>, ..., так что набор по умолчанию теряет свой find,count и т. д. участники?
4 ответа:
какую проблему это решит,
см. ответ Дитмара и ремябеля.
и это меняет то, как работают стандартные контейнеры?
нет, не по умолчанию.
новый шаблон функции-члена перегружает
findetc. позволяет использовать тип, сопоставимый с ключом контейнера, вместо использования самого типа ключа. Смотрите N3465 по настоящее время Хоакин Лопес Муньос для обоснование и подробное, тщательно написанное предложение добавить эту функцию.на встрече в Бристоле РГПВ согласилась с тем, что функция гетерогенного поиска является полезной и желательной, но мы не могли быть уверены, что предложение Хоакина будет безопасным во всех случаях. Предложение N3465 вызвало бы серьезные проблемы для некоторых программ (см. влияние на существующий код). Хоакин подготовил обновленный проект предложения с некоторыми альтернативными реализациями различные компромиссы, которые были очень полезны, помогая LWG понять плюсы и минусы, но все они рисковали каким-то образом нарушить некоторые программы, поэтому не было консенсуса по добавлению этой функции. Мы решили, что хотя было бы небезопасно добавлять эту функцию безоговорочно, было бы безопасно, если бы она была отключена по умолчанию и только "включилась".
ключевое отличие N3657 предложение (которое было пересмотрено в последнюю минуту мной и STL на основе N3465 и более поздний неопубликованный проект Хоакина) должен был добавить
is_transparentвведите в качестве протокола, который может быть использован для выбора новой функциональности.если вы не используете "прозрачный функтор" (т. е. то, что определяет
is_transparenttype), то контейнеры ведут себя так же, как они всегда делали, и это по-прежнему по умолчанию.если вы решите использовать
std::less<>(что является новым для C++14) или другого типа "прозрачный функтор", то вы получаете новый функциональность.используя
std::less<>легко с шаблонами псевдоним:template<typename T, typename Cmp = std::less<>, typename Alloc = std::allocator<T>> using set = std::set<T, Cmp, Alloc>;имя
is_transparentприходит от STL N3421 который добавил "алмазные операторы" в C++14. "Прозрачный функтор" - это тот, который принимает любые типы аргументов (которые не должны быть одинаковыми) и просто передает эти рассуждения к другому оператору. Такой функтор оказывается именно тем, что вы хотите для гетерогенного поиска в ассоциативных контейнерах, поэтому типis_transparentбыл добавлено ко всем алмазным операторам и используется в качестве типа тега, чтобы указать, что новая функциональность должна быть включена в ассоциативных контейнерах. Технически, контейнеры не нуждаются в "прозрачном функторе", только тот, который поддерживает вызов его с гетерогенными типами (например,pointer_compвведите https://stackoverflow.com/a/18940595/981959 не является прозрачным в соответствии с определением STL, но определяетpointer_comp::is_transparentпозволяет использовать его для решения проблемы). Если вы только когда-либо поиск в вашемstd::set<T, C>С ключами типаTилиintзатемCтолько должен быть вызван с аргументами типаTиint(в любом порядке), он не должен быть по-настоящему прозрачным. Мы использовали это имя отчасти потому, что мы не могли придумать лучшего имени (я бы предпочелis_polymorphicпотому что такие функторы используют статический полиморфизм, но уже естьstd::is_polymorphicтип признака, который относится к динамическому полиморфизму).
в C++11 нет шаблонов членов
find(),lower_bound()и т. д. То есть от этого изменения ничего не теряется. Шаблоны элементов были введены с n3657, чтобы разрешить использование гетерогенных Ключей с ассоциативными контейнерами. Я не вижу никакого конкретного примера, где это полезно, за исключением примера, который хорош и плох!The
is_transparentиспользование предназначено для предотвращения нежелательных преобразований. Если шаблоны элементов не были ограничены, существующий код может проходить через объекты непосредственно, который был бы преобразован без шаблонов членов. Пример использования-чехол из n3657 местонахождение объекта вstd::set<std::string>использование строкового литерала: с определением C++11 astd::stringобъект строится при передаче строковых литералов в соответствующую функцию-член. С изменением можно использовать строковый литерал напрямую. Если базовый объект функции сравнения реализован исключительно в терминахstd::stringэто плохо, потому что теперьstd::stringбудет создается для каждого сравнения. С другой стороны, если базовый объект функции сравнения можно взятьstd::stringи строковый литерал, который может избежать построения временного объекта.вложенный элемент
is_transparentтип в объекте функции сравнения предоставляет способ указать, следует ли использовать шаблонную функцию-член: если объект функции сравнения может работать с разнородными аргументами, он определяет этот тип, чтобы указать, что он может работать с разными аргументами эффективно. Например, новые объекты, функции оператора просто делегироватьoperator<()и претендовать на прозрачность. Это, по крайней мере, работаетstd::stringкоторый перегружен меньше, чем операторы, принимающиеchar const*в качестве аргумента. Поскольку эти функциональные объекты также являются новыми, даже если они делают неправильные вещи (т. е. требуют преобразования для некоторого типа), это, по крайней мере, не будет тихим изменением, приводящим к снижению производительности.
ниже все копии-паста от n3657.
вопрос:какова цель сделать компаратор "прозрачным"?
A. ассоциативные функции поиска контейнера (find, lower_bound, upper_bound, equal_range) принимает только аргумент key_type, требующий пользователи, чтобы построить (неявно или явно) объект key_type для выполнения поиска. Это может быть дорого, например, строительство большой объект для поиска в наборе, когда функция компаратора только смотрит на одно поле объекта. Есть сильное желание среди пользователей чтобы иметь возможность поиска с использованием других типов, которые сопоставимы с тип ключа.
вопрос:какую проблему это решит
A. У LWG были проблемы с кодом следующим образом:
std::set<std::string> s = /* ... */; s.find("key");В C++11 это создаст один std:: string временный, а затем сравниваем его с элементами найти ключи.
С изменением, предложенным N3465, функция std::set::find() будет быть неограниченным шаблоном, который будет передавать const char* через для функции компаратора, std:: меньше, что бы постройте временную строку std::для каждого сравнения. РГПВ рассматривал эту проблему производительности как серьезную проблему. Этот шаблон найти() функция также будет препятствовать установлению нуль в контейнер указателей, который приводит к отсутствию ранее действительного кода длиннее компиляции, но это было воспринято как менее серьезная проблема, чем молчать регрессия производительности
вопрос:это меняет то, как работают стандартные контейнеры
А. Это предложение изменяет ассоциативные контейнеры В и перегружая функции-члены поиска с помощью функции-члена шаблоны. Языковые изменения отсутствуют.
вопрос:таким образом, набор по умолчанию теряет свою находку, подсчет и т. д. участники
A. почти весь существующий код C++11 не затронут, потому что член функции отсутствуют, если не используются новые функции библиотеки C++14 как функции сравнения.
цитата Якк,
В C++14, std:: set:: find является функцией шаблона, если Сравните::is_transparent существует. Тип, который вы передаете в не нужно будьте ключом, просто эквивалентным под вашим компаратором.
и n3657,
добавить пункт 13 в 23.2.4 [ассоциативность.потребности]: Шаблоны функций-членов find, lower_bound, upper_bound и equal_range не участвует в разрешении перегрузки, если тип сравнения:: is_transparent
не существуетсуществует.n3421 пример "Прозрачные Операторные Функторы".
на полный код здесь.
Stephan T Lavavej рассказывает о проблемах, когда компилятор продолжает создавать временные функции, и как его предложение прозрачных операторных функторов решит это в c++1y
GoingNative 2013 - не помогайте компилятору (примерно в час)