#c #c 20
#c #c 20 #std-диапазоны
Вопрос:
Возможно ли проецировать на std ::map? Я пытался использовать std ::ranges ::min с проекцией, но, похоже, он выдает ошибки, которые я не могу интерпретировать, почему ему что-то не нравится.
#include <set>
#include <iostream>
#include <ranges>
#include <vector>
#include <iostream>
#include <map>
#include <algorithm>
int main()
{
std::map<int, int> usage_table;
auto lowest = std::ranges::min( std::move(usage_table),
{},
amp;std::map<int,int>::value_type::second );
}
Я мог бы обойти это, но было бы неплохо, если бы это сработало.
Лучшие
Комментарии:
1. Пожалуйста, поделитесь также сообщением об ошибке. Вы имеете в виду использовать
min_element
вместо этого?2. Что значит «проецировать» в этом контексте?
3. Я не могу проверить это отсюда, но вы все еще получаете ошибки, когда удаляете оператор перемещения?
4. разработка диапазонов еще не завершена. Возможно, это ошибка или не реализованная функция.
5. @AdamZahran, вместо элемента, используемого в алгоритме, используется проекция. Например, вместо суммирования клиентов вы можете суммировать их балансы.
Ответ №1:
Посмотрите на std::ranges::min
сигнатуру функции:
template< ranges::input_range R, class Proj = std::identity,
std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
requires std::indirectly_copyable_storable<ranges::iterator_t<R>, ranges::range_value_t<R>*>
constexpr ranges::range_value_t<R> min( Ramp;amp; r, Comp comp = {}, Proj proj = {} );
Он возвращает range_value_t<R>
значения, которые подразумевают value_type
, что диапазон должен быть copyable
, поэтому ranges::min
требуется indirectly_copyable_storable
, который требует indirectly_copyable
, который требует indirectly_writable
:
template<class Out, class T>
concept indirectly_writable =
requires(Outamp;amp; o, Tamp;amp; t) {
*o = std::forward<T>(t);
*std::forward<Out>(o) = std::forward<T>(t);
const_cast<const std::iter_reference_t<Out>amp;amp;>(*o) = std::forward<T>(t);
const_cast<const std::iter_reference_t<Out>amp;amp;>(*std::forward<Out>(o)) =
std::forward<T>(t);
};
Нам нужно *o = std::forward<T>(t)
быть допустимым выражением Out
range_value_t<R>*
, которое есть std::pair<const int, int>*
, но это невозможно, поскольку мы не можем присвоить a std::pair<const int, int>
другому:
std::pair<const int, int> a, b;
// use of deleted function 'std::pair<const int, int>amp; std::pair<const int, int>::operator=(const std::pair<const int, int>amp;)'
a = b;
Так что, к сожалению, std::ranges::min
не может применяться в std::map
:
// constraints not satisfied
std::ranges::min(std::map<int, int>{});
Но если вы хотите найти std::map
минимальное значение its key_type/mapped_type
, вы можете просто использовать адаптер диапазона c 20 std::views::keys/values
, он отлично работает с std::ranges::min
:
std::map<int, int> usage_table{{5, -12}, {3, 4}};
// -12
auto lowest = std::ranges::min(usage_table | std::views::values);
Комментарии:
1. Хорошая находка! Странно, что они сделали такую разницу между
std::ranges:min
(max / minmax) иstd::ranges::min_element
(max_element / minmax_element)2. @JHBonarius,
min
возвращает фактическое значение (не по ссылке), тогдаmin_element
как возвращает итератор.3. @chris, верно, но при использовании проекции это значение снова может быть копируемым типом… Так что теоретически это должно работать… Я думаю, это нужно будет исправить в будущем обновлении стандарта. Я думаю, что концепция проекции слишком нова, так что это проблемы ранней адаптации.
4. @JHBonarius, да, я не удивлюсь, если что-то было упущено из виду.
Ответ №2:
Вместо std::ranges::min
этого вы можете использовать std::ranges::min_element
так:
auto lowest = *std::ranges::min_element(std::move(usage_table),
{},
amp;std::map<int,int>::value_type::second);
Кроме того, непонятно, почему вы move
редактируете map
, похоже, это не делает ничего полезного.
Комментарии:
1. Зависит от того, чего вы хотите нет? Что не так с использованием
std::ranges::min
?2. @JHBonarius Да, кажется, это должно сработать. См. Редактирование 🙂 Я удалил бит, в котором говорилось, что это неправильно. Но, похоже, я не могу заставить его скомпилировать: (
3. реализации диапазонов не являются зрелыми. Это может быть случай ошибки / не реализованной функции
4. @bolov Да, это, безусловно, тоже возможно.
5. Похоже, что он компилируется без перемещения, при этом move it min_element создает std ::ranges::dangling, без итератора, который он создает. Он делает правильные вещи, когда я удаляю перемещение! Спасибо.