微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++20 keys_view 和 values_view 的真正用途是什么?

如何解决C++20 keys_view 和 values_view 的真正用途是什么?

C++20 引入了 ranges::elements_view,它接受​​ viewtuple-like 值,并发出带有 value- 的 view适应view的值类型的第N个元素的类型,其中N是非类型模板参数。 >

[range.elements.view]中,ranges::elements_view的概要定义为:

template<input_­range V,size_t N>
  requires view<V> && has-tuple-element<range_value_t<V>,N> &&
           has-tuple-element<remove_reference_t<range_reference_t<V>>,N> &&
           returnable-element<range_reference_t<V>,N>
class elements_view : public view_interface<elements_view<V,N>> {
  public:
    elements_view() = default;
    constexpr explicit elements_view(V base);
  // ...
};

由于elements_view的构造函数只包含参数V,所以不能直接初始化elements_view而不指定所有模板参数(godbolt):

std::array<std::tuple<int,float>,5> r{};

ranges::elements_view<0>{r};  // error: wrong number of template arguments (1,should be 2)
ranges::elements_view<decltype(views::all(r)),0>{r}; // ok
views::elements<0>(r);                                // ok

这使它失去了其他范围适配器的表达式等价性,例如 ranges::transform_view:

ranges::transform_view{r,[](auto elem) { return std::get<0>(elem); }}; // ok
views::transform(r,[](auto elem) { return std::get<0>(elem); });       // ok

并且在elements_view的基础上,标准另外引入了keys_viewvalues_view,它们都是elements_­view<views​::​all_­t<R>,N>的别名:

template <class R>
using keys_view = elements_view<views::all_t<R>,0>;
template <class R>
using values_view = elements_view<views::all_t<R>,1>;

该标准在 [range.elements#overview-example-2] 中给出了它的用例:

auto historical_figures = map{
  {"lovelace"sv,1815},{"Turing"sv,1912},{"Babbage"sv,1791},{"Hamilton"sv,1936}
};

auto names = keys_view{historical_figures}; 
for (auto&& name : names) {   
  cout << name << ' ';          // prints Babbage Hamilton lovelace Turing  
} 

not quite right,因为我们无法推导出R的类型,所以构造keys_view的唯一方法是指定所有模板参数,就像elements_view:>

auto names = std::ranges::keys_view<decltype(std::views::all(historical_figures))>{historical_figures};

所以 keys_viewvalues_view 似乎完全没用。

在标准中引入它们的目的是什么?我是否错过了他们的一些有用用例?

解决方法

示例中缺少的 pair 问题只是示例中的一个错误;我提交了一个 editorial pull request

更大的问题在于 keys_viewvalues_view 的定义。已提交 LWG 问题,我已为此提供了建议的解决方案。这里的基本问题是

template <class R>
using keys_view = elements_view<views::all_t<R>,0>;

仅在非推导上下文中使用 R,因此它不可能满足别名模板 CTAD 中 the arguments of the alias template be deducible from whatever type that is eventually deduced 的要求。

我提议的决议只是将 keys_view 重新定义为

template <class R>
using keys_view = elements_view<R,0>;

这允许 CTAD 在您已经有视图的情况下工作,并且至少让它有机会与以后添加的 elements_view 上的任何演绎指南一起工作。我探索了添加此类指南的可能性,但当前的别名模板 CTAD 实现过于破碎,无法对其进行测试,因此我不太愿意提出建议。

有了这个改动,你至少可以写

auto names = keys_view{views::all(historical_figures)}; 
for (auto&& name : names) {   
  cout << name << ' ';          // prints Babbage Hamilton Lovelace Turing  
} 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。