Проецирование на std:: map с помощью std ::ranges ::min

#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, без итератора, который он создает. Он делает правильные вещи, когда я удаляю перемещение! Спасибо.