Skip to content

Commit

Permalink
Adopt LWG-3546 common_iterator's postfix-proxy is not quite right (
Browse files Browse the repository at this point in the history
…#1991)

Addresses #1965

Co-authored-by: S. B. Tam <cpplearner@outlook.com>
Co-authored-by: Casey Carter <Casey@Carter.net>
  • Loading branch information
3 people committed Oct 9, 2021
1 parent 48ac24c commit 65a346d
Showing 1 changed file with 39 additions and 13 deletions.
52 changes: 39 additions & 13 deletions stl/inc/iterator
Original file line number Diff line number Diff line change
Expand Up @@ -804,23 +804,23 @@ public:
};

// clang-format off
template <class _Iter>
concept _Use_postfix_proxy = !requires(_Iter& __it) { { *__it++ } -> _Can_reference; }
&& indirectly_readable<_Iter> // Per LWG-3601
&& constructible_from<iter_value_t<_Iter>, iter_reference_t<_Iter>>
&& move_constructible<iter_value_t<_Iter>>;

template <input_or_output_iterator _Iter, sentinel_for<_Iter> _Se>
requires (!same_as<_Iter, _Se> && copyable<_Iter>)
class common_iterator {
// clang-format on
private:
class _Proxy {
private:
struct _Proxy_base {
iter_value_t<_Iter> _Keep;

public:
explicit _Proxy(iter_reference_t<_Iter>&& _Right) noexcept(
is_nothrow_move_constructible_v<iter_value_t<_Iter>>) // strengthened
: _Keep(_STD move(_Right)) {}

_NODISCARD const iter_value_t<_Iter>* operator->() const noexcept /* strengthened */ {
return _STD addressof(_Keep);
}
explicit _Proxy_base(iter_reference_t<_Iter>&& _Right) noexcept(
is_nothrow_constructible_v<iter_value_t<_Iter>, iter_reference_t<_Iter>>) // strengthened
: _Keep(_STD forward<iter_reference_t<_Iter>>(_Right)) {}
};

public:
Expand Down Expand Up @@ -874,20 +874,31 @@ public:
// clang-format off
_NODISCARD decltype(auto) operator->() const
requires indirectly_readable<const _Iter>
&& (_Has_member_arrow<_Iter> || is_reference_v<iter_reference_t<_Iter>>
&& (_Has_member_arrow<const _Iter&> || is_reference_v<iter_reference_t<_Iter>>
|| constructible_from<iter_value_t<_Iter>, iter_reference_t<_Iter>>) {
// clang-format on
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_iter,
"common_iterator can only be dereferenced if it holds an iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
if constexpr (is_pointer_v<_Iter> || _Has_member_arrow<_Iter>) {
if constexpr (_Has_member_arrow<const _Iter&> || is_pointer_v<_Iter>) {
return (_Val._Iterator); // NB: () are necessary for decltype(auto)
} else if constexpr (is_reference_v<iter_reference_t<_Iter>>) {
auto&& _Tmp = *_Val._Iterator;
return _STD addressof(_Tmp);
} else {
return _Proxy{*_Val._Iterator};
class _Arrow_proxy : private _Proxy_base {
public:
friend common_iterator;

using _Proxy_base::_Proxy_base;

_NODISCARD const iter_value_t<_Iter>* operator->() const noexcept /* strengthened */ {
return _STD addressof(this->_Keep);
}
};

return _Arrow_proxy{*_Val._Iterator};
}
}

Expand All @@ -909,6 +920,21 @@ public:
common_iterator _Tmp = *this;
++_Val._Iterator;
return _Tmp;
} else if constexpr (_Use_postfix_proxy<_Iter>) {
class _Postfix_proxy : private _Proxy_base {
public:
friend common_iterator;

using _Proxy_base::_Proxy_base;

_NODISCARD const iter_value_t<_Iter>& operator*() const noexcept /* strengthened */ {
return this->_Keep;
}
};

_Postfix_proxy _Tmp{*_Val._Iterator};
++_Val._Iterator;
return _Tmp;
} else {
return _Val._Iterator++;
}
Expand Down

0 comments on commit 65a346d

Please sign in to comment.