【问题标题】:Projecting on a std::map with std::ranges::min使用 std::ranges::min 在 std::map 上投影
【发布时间】:2021-12-06 06:10:28
【问题描述】:

是否可以在 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), 
                                   {}, 
                                   &std::map<int,int>::value_type::second );
}

我可以解决它,但如果这个班轮工作会很好。

最好的

【问题讨论】:

  • 请同时分享错误信息。您的意思是改用min_element 吗?
  • 在这种情况下“投影”是什么意思?
  • 我无法从这里检查它,但是您是否仍然收到删除 move 语句的错误?
  • ranges 开发还不成熟。也许可能是一个错误或未实现的功能。
  • @AdamZahran,不是算法中使用的元素,而是使用投影。例如,您可以将他们的余额相加,而不是对客户求和。

标签: c++ c++20


【解决方案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( R&& r, Comp comp = {}, Proj proj = {} );

它返回range_value_t&lt;R&gt;,这意味着value_type的范围需要是copyable,所以ranges::min需要indirectly_copyable_storable需要indirectly_copyable需要indirectly_writable

template<class Out, class T>
  concept indirectly_writable =
    requires(Out&& o, T&& t) {
      *o = std::forward<T>(t);
      *std::forward<Out>(o) = std::forward<T>(t);
      const_cast<const std::iter_reference_t<Out>&&>(*o) = std::forward<T>(t);
      const_cast<const std::iter_reference_t<Out>&&>(*std::forward<Out>(o)) =
        std::forward<T>(t);
    };

我们需要*o = std::forward&lt;T&gt;(t) 是有效的表达式,其中Outrange_value_t&lt;R&gt;*,也就是std::pair&lt;const int, int&gt;*,但这是不可能的,因为我们不能将std::pair&lt;const int, int&gt; 分配给其他人:

std::pair<const int, int> a, b;
// use of deleted function 'std::pair<const int, int>& std::pair<const int, int>::operator=(const std::pair<const int, int>&)'
a = b;

所以很遗憾,std::ranges::min 不能申请 std::map

// constraints not satisfied
std::ranges::min(std::map<int, int>{});

但是如果你想找到std::map的最小值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);

【讨论】:

  • 好发现!奇怪的是他们在std::ranges:min(max/minmax) 和std::ranges::min_element(max_element/minmax_element) 之间做出了如此大的区别
  • @JHBonarius, min 返回一个实际值(不是通过引用),而 min_element 返回一个迭代器。
  • @chris,是的,但是使用投影该值可以再次成为可复制类型......所以理论上它应该可以工作......我认为这必须在未来的更新中修复标准。我认为投影的概念太新了,所以这是早期的适应问题。
  • @JHBonarius,是的,如果有什么被忽略,我不会感到惊讶。
【解决方案2】:

您可以像这样使用std::ranges::min_element 而不是std::ranges::min

auto lowest = *std::ranges::min_element(std::move(usage_table), 
                                        {}, 
                                        &std::map<int,int>::value_type::second);

另外,不清楚你为什么要movemap,它似乎没有任何用处。

【讨论】:

  • 取决于你想要什么不?使用std::ranges::min 有什么问题?
  • @JHBonarius 是的,它似乎应该工作。请参阅编辑 :) 我删除了说它是错误的位。但我实际上似乎无法编译:(
  • 范围实现还不成熟。这可能是错误/未实现功能的情况
  • @bolov 是的,这当然也是可能的。
  • 看起来它在没有移动的情况下编译,移动它 min_element 产生一个 std::ranges::dangling,没有它在迭代器处产生。当我移除移动时,它会做正确的事情!谢谢。
猜你喜欢
  • 1970-01-01
  • 2021-05-30
  • 2020-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-15
  • 2021-05-11
相关资源
最近更新 更多