c++ - C++20 keys_view 和 values_view 的真正目的是什么?

标签 c++ c++20 std-ranges

C++20 介绍 ranges::elements_view ,它接受 view 类似元组的值,并发出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>;

如果您已经有一个 View ,这允许 CTAD 工作,并且至少让它有机会使用以后添加的任何关于 elements_view 的推导指南。我探索了添加此类指南的可能性,但当前的别名模板 CTAD 实现太破,无法对其进行测试,所以我觉得建议一个不太方便。

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

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

关于c++ - C++20 keys_view 和 values_view 的真正目的是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67752995/

相关文章:

c++ - 如何为启发式函数编写C++概念

c++ - 用户定义的容器不适用于 std::ranges

c++ - std::views::keys 是否保证能与任何对/元组类型正常工作?

c++ - 如何使用成员函数进行标准库范围操作

c++ - 你会推荐我什么项目来加快 C++ 的速度

c++ - 通过 unsigned char 别名访问对象,加载和存储时会发生什么?

c++ - 每次运行时计算不同的数字

c++ - 简洁的方式来指定我不关心函数参数的模板参数?

c++ - Qt LEFT CTRL键代码

c++ - 遍历具有 int 类型的模板化 C++ 函数