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_view和values_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 实现过于破碎,无法对其进行测试,因此我不太愿意提出建议。
通过此更改,您至少可以编写