Skip to content

Commit 4d23b38

Browse files
committed
LWG3502 elements_view should not be allowed to return dangling references
1 parent 3519e76 commit 4d23b38

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

source/ranges.tex

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6310,10 +6310,13 @@
63106310
{ get<N>(t) } -> convertible_to<const tuple_element_t<N, T>&>;
63116311
};
63126312

6313+
template<class T, size_t N>
6314+
concept @\defexposconcept{returnable-element}@ = is_reference_v<T> || move_constructible<tuple_element_t<N, T>>;
63136315

63146316
template<@\libconcept{input_range}@ V, size_t N>
63156317
requires @\libconcept{view}@<V> && @\exposconcept{has-tuple-element}@<range_value_t<V>, N> &&
6316-
@\exposconcept{has-tuple-element}@<remove_reference_t<range_reference_t<V>>, N>
6318+
@\exposconcept{has-tuple-element}@<remove_reference_t<range_reference_t<V>>, N> &&
6319+
@\exposconcept{returnable-element}@<range_reference_t<V>, N>
63176320
class elements_view : public view_interface<elements_view<V, N>> {
63186321
public:
63196322
elements_view() = default;
@@ -6374,12 +6377,16 @@
63746377
namespace std::ranges {
63756378
template<@\libconcept{input_range}@ V, size_t N>
63766379
requires @\libconcept{view}@<V> && @\exposconcept{has-tuple-element}@<range_value_t<V>, N> &&
6377-
@\exposconcept{has-tuple-element}@<remove_reference_t<range_reference_t<V>>, N>
6380+
@\exposconcept{has-tuple-element}@<remove_reference_t<range_reference_t<V>>, N> &&
6381+
@\exposconcept{returnable-element}@<range_reference_t<V>, N>
63786382
template<bool Const>
63796383
class elements_view<V, N>::@\exposid{iterator}@ { // \expos
63806384
using @\exposid{Base}@ = @\exposid{maybe-const}@<Const, V>; // \expos
63816385

6382-
iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>();
6386+
iterator_t<@\exposid{Base}@> @\exposid{current_}@ = iterator_t<@\exposid{Base}@>(); // \expos
6387+
6388+
static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); // \expos
6389+
63836390
public:
63846391
using iterator_category = typename iterator_traits<iterator_t<@\exposid{Base}@>>::iterator_category;
63856392
using value_type = remove_cvref_t<tuple_element_t<N, range_value_t<@\exposid{Base}@>>>;
@@ -6395,7 +6402,7 @@
63956402
constexpr iterator_t<@\exposid{Base}@> base() &&;
63966403

63976404
constexpr decltype(auto) operator*() const
6398-
{ return get<N>(*@\exposid{current_}@); }
6405+
{ return @\exposid{get-element}@(@\exposid{current_}@); }
63996406

64006407
constexpr @\exposid{iterator}@& operator++();
64016408
constexpr void operator++(int);
@@ -6411,7 +6418,7 @@
64116418

64126419
constexpr decltype(auto) operator[](difference_type n) const
64136420
requires @\libconcept{random_access_range}@<@\exposid{Base}@>
6414-
{ return get<N>(*(@\exposid{current_}@ + n)); }
6421+
{ return @\exposid{get-element}@(@\exposid{current_}@ + n); }
64156422

64166423
friend constexpr bool operator==(const @\exposid{iterator}@& x, const @\exposid{iterator}@& y)
64176424
requires @\libconcept{equality_comparable}@<iterator_t<@\exposid{Base}@>>;
@@ -6439,6 +6446,26 @@
64396446
}
64406447
\end{codeblock}
64416448

6449+
\indexlibrarymember{\exposid{get-element}}{elements_view::iterator}%
6450+
\begin{itemdecl}
6451+
static constexpr decltype(auto) @\exposid{get-element}@(const iterator_t<@\exposid{Base}@>& i); // \expos
6452+
\end{itemdecl}
6453+
6454+
\begin{itemdescr}
6455+
\pnum
6456+
\effects
6457+
Equivalent to:
6458+
\begin{codeblock}
6459+
if constexpr (is_reference_v<range_reference_t<@\exposid{Base}@>>) {
6460+
return get<N>(*i);
6461+
}
6462+
else {
6463+
using E = remove_cv_t<tuple_element_t<N, range_reference_t<@\exposid{Base}@>>>;
6464+
return static_cast<E>(get<N>(*i));
6465+
}
6466+
\end{codeblock}
6467+
\end{itemdescr}
6468+
64426469
\indexlibraryctor{elements_view::iterator}%
64436470
\begin{itemdecl}
64446471
constexpr explicit @\exposid{iterator}@(iterator_t<@\exposid{Base}@> current);
@@ -6717,7 +6744,8 @@
67176744
namespace std::ranges {
67186745
template<@\libconcept{input_range}@ V, size_t N>
67196746
requires @\libconcept{view}@<V> && @\placeholder{has-tuple-element}@<range_value_t<V>, N> &&
6720-
@\placeholder{has-tuple-element}@<remove_reference_t<range_reference_t<V>>, N>
6747+
@\placeholder{has-tuple-element}@<remove_reference_t<range_reference_t<V>>, N> &&
6748+
@\exposconcept{returnable-element}@<range_reference_t<V>, N>
67216749
template<bool Const>
67226750
class elements_view<V, N>::@\exposid{sentinel}@ { // \expos
67236751
private:

0 commit comments

Comments
 (0)