libstdc++: Fix elements_view::operator* and operator[] [LWG 3502]

While we're modifying elements_view, this also implements the one-line
resolution of LWG 3492.

libstdc++-v3/ChangeLog:

	* include/std/ranges (__detail::__returnable_element): New
	concept.
	(elements_view): Use this concept in its constraints.  Add
	missing private access specifier.
	(elements_view::_S_get_element): Define as per LWG 3502.
	(elements_view::operator*, elements_view::operator[]): Use
	_S_get_element.
	(elements_view::operator++): Remove unnecessary constraint
	as per LWG 3492.
	* testsuite/std/ranges/adaptors/elements.cc (test05): New test.
This commit is contained in:
Patrick Palka 2021-04-08 16:45:22 -04:00
parent be8d5f99f5
commit c7fe68f365
2 changed files with 38 additions and 4 deletions

View File

@ -3234,6 +3234,10 @@ namespace views::__adaptor
{ std::get<_Nm>(__t) } { std::get<_Nm>(__t) }
-> convertible_to<const tuple_element_t<_Nm, _Tp>&>; -> convertible_to<const tuple_element_t<_Nm, _Tp>&>;
}; };
template<typename _Tp, size_t _Nm>
concept __returnable_element
= is_reference_v<_Tp> || move_constructible<tuple_element_t<_Nm, _Tp>>;
} }
template<input_range _Vp, size_t _Nm> template<input_range _Vp, size_t _Nm>
@ -3241,6 +3245,7 @@ namespace views::__adaptor
&& __detail::__has_tuple_element<range_value_t<_Vp>, _Nm> && __detail::__has_tuple_element<range_value_t<_Vp>, _Nm>
&& __detail::__has_tuple_element<remove_reference_t<range_reference_t<_Vp>>, && __detail::__has_tuple_element<remove_reference_t<range_reference_t<_Vp>>,
_Nm> _Nm>
&& __detail::__returnable_element<range_reference_t<_Vp>, _Nm>
class elements_view : public view_interface<elements_view<_Vp, _Nm>> class elements_view : public view_interface<elements_view<_Vp, _Nm>>
{ {
public: public:
@ -3298,10 +3303,23 @@ namespace views::__adaptor
template<bool _Const> template<bool _Const>
struct _Iterator struct _Iterator
{ {
private:
using _Base = __detail::__maybe_const_t<_Const, _Vp>; using _Base = __detail::__maybe_const_t<_Const, _Vp>;
iterator_t<_Base> _M_current = iterator_t<_Base>(); iterator_t<_Base> _M_current = iterator_t<_Base>();
static constexpr decltype(auto)
_S_get_element(const iterator_t<_Base>& __i)
{
if constexpr (is_reference_v<range_reference_t<_Base>>)
return std::get<_Nm>(*__i);
else
{
using _Et = remove_cv_t<tuple_element_t<_Nm, range_reference_t<_Base>>>;
return static_cast<_Et>(std::get<_Nm>(*__i));
}
}
friend _Iterator<!_Const>; friend _Iterator<!_Const>;
public: public:
@ -3334,8 +3352,8 @@ namespace views::__adaptor
{ return std::move(_M_current); } { return std::move(_M_current); }
constexpr decltype(auto) constexpr decltype(auto)
operator*() const operator*() const
{ return std::get<_Nm>(*_M_current); } { return _S_get_element(_M_current); }
constexpr _Iterator& constexpr _Iterator&
operator++() operator++()
@ -3345,7 +3363,7 @@ namespace views::__adaptor
} }
constexpr void constexpr void
operator++(int) requires (!forward_range<_Base>) operator++(int)
{ ++_M_current; } { ++_M_current; }
constexpr _Iterator constexpr _Iterator
@ -3390,7 +3408,7 @@ namespace views::__adaptor
constexpr decltype(auto) constexpr decltype(auto)
operator[](difference_type __n) const operator[](difference_type __n) const
requires random_access_range<_Base> requires random_access_range<_Base>
{ return std::get<_Nm>(*(_M_current + __n)); } { return _S_get_element(_M_current + __n); }
friend constexpr bool friend constexpr bool
operator==(const _Iterator& __x, const _Iterator& __y) operator==(const _Iterator& __x, const _Iterator& __y)

View File

@ -100,6 +100,21 @@ test04()
static_assert(!requires { 0 | elements; }); static_assert(!requires { 0 | elements; });
} }
void
test05()
{
// LWG 3502
std::vector<int> vec = {42};
auto r1 = vec
| views::transform([](auto c) { return std::make_tuple(c, c); })
| views::keys;
VERIFY( ranges::equal(r1, (int[]){42}) );
std::tuple<int, int> a[] = {{1,2},{3,4}};
auto r2 = a | views::keys;
VERIFY( r2[0] == 1 && r2[1] == 3 );
}
int int
main() main()
{ {
@ -107,4 +122,5 @@ main()
test02(); test02();
test03(); test03();
test04(); test04();
test05();
} }