Компараторы в std:: очередь приоритетов

есть ли причина, по которой std::priority_queueконструктор принимает компаратор по постоянной ссылке? Что делать, если компаратор выходит за рамки?

Я думал об этом в контексте возможного перемещения компаратора, как указал @LightnessRacesInOrbit!

Мне жаль, если об этом уже было сообщение. Я не смог его найти!

3 ответов


Я никогда не думал об этом раньше, и const-ref действительно немного вводит в заблуждение. Однако сигнатура функции была придумана до появления семантики перемещения, и стало модным принимать все по значению. Действительно, компаратор копируется!

[C++14: 23.6.4.1/4]: эффекты: инициализирует comp С x и c С y (копировать построение или перемещать построение по мере необходимости); вызовы c.insert(c.end(), first, last); и, наконец, вызовы make_heap(c.begin(), c.end(), comp).

лямбды не копируются, но они are копировать-конструктивный, поэтому здесь нет проблем.

[C++14: 5.1.2/20]: тип закрытия, связанный с лямбда-выражение имеет удаленный (8.4.3) конструктор по умолчанию и оператор назначения удаленной копии. Он имеет неявно объявленный конструктор копирования (12.8) и может иметь неявно объявленный конструктор перемещения (12.8). [..]

предотвращает ли это перемещение-построение самого компаратора? Да, это так. Я собираюсь предположить, что это соглашение о том, чтобы взять компаратор const-ref, а затем скопировать его, происходит от дней STL, задолго до семантики перемещения. Я полагаю, что серьезно не рассматривалось добавление перегрузок, чтобы взять компаратор по значению, потому что это добавляет сложность, и у вас не должно быть сложного, улучшающего перемещение компаратора в первую очередь (дайте им состояние, конечно, но не слишком много). И все же это ... --12-->мая стоит поднять с комитетом, если вы можете придумать надежный вариант использования для перемещения компаратора.


Он не выходит за рамки-это копия, построенная в контейнер. Описание на cppreference.com состояния:

explicit priority_queue( const Compare& compare = Compare(),
                         const Container& cont = Container() );

Copy-создает базовый контейнер c с содержимым cont. Copy-создает функтор сравнения comp с содержимым compare. Вызовы std:: make_heap(c.begin (), c.end (), comp). Это также конструктор по умолчанию.

существуют различные другие формы конструктора, но во всех случаи внутренний компаратор или экземпляр-или двигает-построен от одного поставленного.


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

вы можете использовать лямбда-выражение в качестве компаратора с помощью std::function<bool(const T&, const T&)> как тип компаратора, или сразу:

auto comp = [](int x, int y) { return x > y; };
std::priority_queue<int, std::vector<int>, decltype(comp)> q(comp);

вы можете облегчить это с помощью вспомогательной функции:

template<typename T, typename Compare>
auto make_priority_queue(Compare&& comp) {
    return std::priority_queue<T, std::vector<T>, Compare>(std::forward<Compare>(comp));
}

int main() {
    auto q = make_priority_queue<int>([](int x, int y) { return x > y; });
}