Заполнение другого контейнера неизбежно.Но вам не нужно перемещать или копировать свои собственные данные.Вы можете использовать std::list::splice
для извлечения и повторной вставки узлов, которые вы хотите обработать в отсортированном порядке.
using list_t = std::list<widget>;
void process(list_t& in, list_t::const_iterator begin, list_t::const_iterator end) {
list_t sorter;
sorter.splice(sorter.end(), in, begin, end);
sorter.sort();
in.splice(end, sorter);
}
Функция переносит узлы, которые вы хотите отсортировать, в список сортировщика (первый аргумент итератора - это позиция, перед которой вставляются узлы, в данном случае это конец списка).
Список сортировщика сортируется (очевидно), а затем отсортированный контент переносится обратно в список источниковточно в исходный поддиапазон, который он изначально заполнил.
Как прокомментировал @TC Следующий шаг - обобщить его.Его можно превратить в шаблон, похожий на этот:
template<class List, class Compare = std::less<>>
void sort_subrange(List& in,
typename List::const_iterator begin,
typename List::const_iterator end,
Compare c = {}) {
List sorter(in.get_allocator());
sorter.splice(sorter.end(), in, begin, end);
[[maybe_unused]] ScopeGuard sg([&]() { in.splice(end, sorter); });
sorter.sort(std::move(c));
}
В качестве аргумента здесь также используется компаратор, а sorter
создается с копией распределителя входных данных для максимальной универсальности.Сращивание выполняется в выбранной нами области видимости, чтобы поддержать случай, когда выбрасывает функция сравнения, поэтому наши базы теперь покрыты.
Вот живой пример , с наивным и несколько глупым применением ограждения области видимости для целей изложения.