TherealpurposeofC++20keys_viewandvalues_view?

C++20 introduced ranges::elements_view, which accepts a view of tuple-like values, and issues a view with a value-type of the Nth element of the adapted view's value-type, where N is the non-type template parameter.

In [range.elements.view], the synopsis of ranges::elements_view is defined as:

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);
  // ...
};

Since the constructor of elements_view only contains the parameter V, it is impossible to initialize elements_view directly without specifying all template parameters (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

This makes it lose the expression equivalence of other range adaptors such as 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

And on the basis of elements_view, the standard additionally introduces keys_view and values_view, which are both aliases for 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>;

The standard gives its use cases in [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  
} 

which is not quite right since we cannot deduce the type of R, the only way to construct keys_view is to specify all template parameters, just like elements_view:

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

So keys_view and values_view seem to be completely useless.

What is the purpose of introducing them in the standard? Did I miss some of their useful use cases?

回答

pair示例中缺少的问题只是示例中的一个错误;我提交了一个编辑拉取请求。

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

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

用途R只有在非推测的背景下,因此它不能可能是有史以来满足别名模板CTAD的要求,即别名模板的论据是从任何类型的最终推导出可推论。

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

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

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

通过此更改,您至少可以编写


以上是TherealpurposeofC++20keys_viewandvalues_view?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>