Что такое прозрачные компараторы?

в 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, etc. члены?

4 ответов


какую проблему это решит,

см. ответ Дитмара и ремябеля.

и это меняет то, как работают стандартные контейнеры?

нет, не по умолчанию.

новый шаблон функции-члена перегружает find etc. позволяет использовать тип, сопоставимый с ключом контейнера, вместо использования самого типа ключа. См.N3465 Хоакин Mª Лопес Муньос для обоснование и подробное, тщательно написанное предложение добавить эту функцию.

влияние на существующий код). Хоакин подготовил обновленный проект предложения с некоторыми альтернативными реализациями с различные компромиссы, которые были очень полезны, помогая LWG понять плюсы и минусы, но все они рисковали каким-то образом нарушить некоторые программы, поэтому не было консенсуса, чтобы добавить эту функцию. Мы решили, что, хотя было бы небезопасно добавлять функцию безоговорочно, было бы безопасно, если бы она была отключена по умолчанию и только "выбрать".

ключевое отличие N3657 предложение (которое было пересмотрено в последнюю минуту мной и STL на основе N3465 и более поздний неопубликованный проект Хоакина) должен был добавить is_transparent введите в качестве протокола, который можно использовать для выбора новой функции.

если вы не используете "прозрачный функтор" (т. е. то, что определяет is_transparent type), то контейнеры ведут себя так же, как и всегда, и это все еще значение по умолчанию.

если вы решите использовать 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 был добавлена ко всем операторам diamond и используется в качестве типа тега для указания новой функциональности должна быть включена в ассоциативных контейнерах. Технически контейнерам не нужен "прозрачный функтор", только тот, который поддерживает его вызов с гетерогенными типами (например,pointer_comp типа https://stackoverflow.com/a/18940595/981959 не является прозрачным по определению стл, но определение pointer_comp::is_transparent позволяет использовать его для решения проблемы). Если вы только когда-либо lookup в вашем std::set<T, C> С ключами типа T или int затем C только должен быть вызван с аргументами типа T и int (в любом порядке), он не должен быть по-настоящему прозрачным. Мы использовали это имя отчасти потому, что мы не могли придумать лучшего имени (я бы предпочел is_polymorphic потому что такие функторы используют статический полиморфизм, но уже есть std::is_polymorphic тип признака, который относится к динамическому полиморфизму).


в C++11 нет шаблонов членов find(), lower_bound(), etc. То есть, ничто не теряется от этого изменения. Шаблоны элементов были введены с n3657, чтобы гетерогенные ключи использовались с ассоциативными контейнерами. Я не вижу конкретного примера, где это полезно, за исключением примера, который хорош и плох!

на is_transparent использовать для того, чтобы избежать нежелательных преобразований. Если шаблоны элементов не ограничены, существующий код может проходить через объекты непосредственно, который был бы преобразован без шаблонов членов. Пример использования из n3657-это поиск объекта в std::set<std::string> использование строкового литерала: с определением C++11 a std::string объект создается при передаче строковых литералов в соответствующую функцию-член. С изменением можно использовать строковый литерал напрямую. Если базовый объект функции сравнения реализован исключительно в терминах std::string это плохо, потому что теперь std::string будет создано для каждого сравнения. С другой стороны, если базовый объект функции сравнения можно взять std::string и строковый литерал, который может избежать создания временного объекта.

вложенный элемент is_transparent тип в объекте функции сравнения предоставляет способ указать, следует ли использовать шаблонную функцию-член: если объект функции сравнения может иметь дело с гетерогенными аргументами, он определяет этот тип, чтобы указать, что он может иметь дело с различными аргументами эффективно. Например, объекты функции new operator просто делегируют в 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:: less, которая создайте временную строку std::для каждого сравнения. РГПВ рассматривал эту проблему производительности как серьезную проблему. Этот функция template find () также предотвратит поиск NULL в a контейнер указателей, который вызывает ранее действительный код no длиннее компилировать, но это рассматривалось как менее серьезная проблема, чем молчание регрессия производительности

вопрос:это меняет работу стандартных контейнеров

А. Это предложение изменяет ассоциативные контейнеры В и путем перегрузки функций-членов lookup функцией-членом шаблоны. Никаких языковых изменений.

вопрос:таким образом, набор по умолчанию теряет свою находку, счет и т. д. члены

A. почти весь существующий код C++11 не изменяется, потому что член функции отсутствуют, если не используются новые функции библиотеки C++14 как функции сравнения.

цитата Якк,

В C++14 std:: set:: find является функцией шаблона, если Сравнить:: is_transparent существует. Типа вы передаете не нужно будьте ключевым, просто эквивалентным под вашим компаратором.

и n3657,

добавить пункт 13 в 23.2.4 [ассоциативность.reqmts]: Шаблоны функцию-член find, lower_bound, объектом upper_bound и equal_range не участвует в разрешении перегрузки, если тип сравнения:: is_transparent не существует существует.

n3421 пример "Прозрачные Функторы Оператора".

на полный код здесь.


Стефан Т Лававей говорит о проблемах, где компилятор продолжает создавать временные, и как его предложение прозрачных функторов операторов решит это в c++1y

GoingNative 2013 - не помогайте компилятору (примерно в час)