/// \file // Range v3 library // // Copyright Eric Niebler 2014-present // Copyright Casey Carter 2016 // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_ITERATOR_BASIC_ITERATOR_HPP #define RANGES_V3_ITERATOR_BASIC_ITERATOR_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_MULTIPLE_ASSIGNMENT_OPERATORS namespace ranges { /// \addtogroup group-iterator Iterator /// @{ /// template struct basic_mixin : private box { CPP_member constexpr CPP_ctor(basic_mixin)()( // noexcept(std::is_nothrow_default_constructible::value) // requires default_constructible) : box{} {} CPP_member constexpr explicit CPP_ctor(basic_mixin)(T && t)( // noexcept(std::is_nothrow_move_constructible::value) // requires move_constructible) : box(detail::move(t)) {} CPP_member constexpr explicit CPP_ctor(basic_mixin)(T const & t)( // noexcept(std::is_nothrow_copy_constructible::value) // requires copy_constructible) : box(t) {} protected: using box::get; }; /// \cond namespace detail { template using cursor_reference_t = decltype(range_access::read(std::declval())); // Compute the rvalue reference type of a cursor template auto cursor_move(Cur const & cur, int) -> decltype(range_access::move(cur)); template auto cursor_move(Cur const & cur, long) -> aux::move_t>; template using cursor_rvalue_reference_t = decltype(detail::cursor_move(std::declval(), 42)); // Define conversion operators from the proxy reference type // to the common reference types, so that basic_iterator can model readable // even with getters/setters. template struct proxy_reference_conversion { operator Head() const noexcept(noexcept(Head(Head(std::declval().read_())))) { return Head(static_cast(this)->read_()); } }; // Collect the reference types associated with cursors template struct cursor_traits_ { private: struct private_ {}; public: using value_t_ = private_; using reference_t_ = private_; using rvalue_reference_t_ = private_; using common_refs = meta::list<>; }; template struct cursor_traits_ { using value_t_ = range_access::cursor_value_t; using reference_t_ = cursor_reference_t; using rvalue_reference_t_ = cursor_rvalue_reference_t; private: using R1 = reference_t_; using R2 = common_reference_t; using R3 = common_reference_t; using tmp1 = meta::list; using tmp2 = meta::if_>, tmp1, meta::push_back>; using tmp3 = meta::if_>, tmp2, meta::push_back>; public: using common_refs = meta::unique>; }; template using cursor_traits = cursor_traits_>; template using cursor_value_t = typename cursor_traits::value_t_; template struct basic_proxy_reference_; template using basic_proxy_reference = basic_proxy_reference_>; // The One Proxy Reference type to rule them all. basic_iterator uses this // as the return type of operator* when the cursor type has a set() member // function of the correct signature (i.e., if it can accept a value_type &&). template*/> struct RANGES_EMPTY_BASES basic_proxy_reference_ : cursor_traits // The following adds conversion operators to the common reference // types, so that basic_proxy_reference can model readable , meta::inherit::common_refs, meta::bind_front, basic_proxy_reference_>>> { private: Cur * cur_; template friend struct basic_proxy_reference_; template friend struct proxy_reference_conversion; using typename cursor_traits::value_t_; using typename cursor_traits::reference_t_; using typename cursor_traits::rvalue_reference_t_; static_assert((bool)common_reference_with, "Your readable and writable cursor must have a value type and " "a reference type that share a common reference type. See the " "ranges::common_reference type trait."); // BUGBUG make these private: public: constexpr reference_t_ read_() const noexcept( noexcept(reference_t_(range_access::read(std::declval())))) { return range_access::read(*cur_); } template constexpr void write_(T && t) const { range_access::write(*cur_, (T &&) t); } // public: basic_proxy_reference_() = default; basic_proxy_reference_(basic_proxy_reference_ const &) = default; template(typename OtherCur)( /// \pre requires convertible_to) constexpr basic_proxy_reference_( basic_proxy_reference const & that) noexcept : cur_(that.cur_) {} constexpr explicit basic_proxy_reference_(Cur & cur) noexcept : cur_(&cur) {} CPP_member constexpr auto operator=(basic_proxy_reference_ && that) -> CPP_ret(basic_proxy_reference_ &)( /// \pre requires readable_cursor) { return *this = that; } CPP_member constexpr auto operator=(basic_proxy_reference_ const & that) -> CPP_ret(basic_proxy_reference_ &)( /// \pre requires readable_cursor) { this->write_(that.read_()); return *this; } CPP_member constexpr auto operator=(basic_proxy_reference_ && that) const -> CPP_ret(basic_proxy_reference_ const &)( /// \pre requires readable_cursor) { return *this = that; } CPP_member constexpr auto operator=(basic_proxy_reference_ const & that) const -> CPP_ret(basic_proxy_reference_ const &)( /// \pre requires readable_cursor) { this->write_(that.read_()); return *this; } template(typename OtherCur)( /// \pre requires readable_cursor AND writable_cursor>) constexpr basic_proxy_reference_ & // operator=(basic_proxy_reference && that) { return *this = that; } template(typename OtherCur)( /// \pre requires readable_cursor AND writable_cursor>) constexpr basic_proxy_reference_ & // operator=(basic_proxy_reference const & that) { this->write_(that.read_()); return *this; } template(typename OtherCur)( /// \pre requires readable_cursor AND writable_cursor>) constexpr basic_proxy_reference_ const & // operator=(basic_proxy_reference && that) const { return *this = that; } template(typename OtherCur)( /// \pre requires readable_cursor AND writable_cursor>) constexpr basic_proxy_reference_ const & // operator=(basic_proxy_reference const & that) const { this->write_(that.read_()); return *this; } template(typename T)( /// \pre requires writable_cursor) constexpr basic_proxy_reference_ & operator=(T && t) // { this->write_((T &&) t); return *this; } template(typename T)( /// \pre requires writable_cursor) constexpr basic_proxy_reference_ const & operator=(T && t) const { this->write_((T &&) t); return *this; } }; template(typename Cur, bool IsReadable)( /// \pre requires readable_cursor AND equality_comparable>) constexpr bool operator==(basic_proxy_reference_ const & x, cursor_value_t const & y) { return x.read_() == y; } template(typename Cur, bool IsReadable)( /// \pre requires readable_cursor AND equality_comparable>) constexpr bool operator!=(basic_proxy_reference_ const & x, cursor_value_t const & y) { return !(x == y); } template(typename Cur, bool IsReadable)( /// \pre requires readable_cursor AND equality_comparable>) constexpr bool operator==(cursor_value_t const & x, basic_proxy_reference_ const & y) { return x == y.read_(); } template(typename Cur, bool IsReadable)( /// \pre requires readable_cursor AND equality_comparable>) constexpr bool operator!=(cursor_value_t const & x, basic_proxy_reference_ const & y) { return !(x == y); } template(typename Cur, bool IsReadable)( /// \pre requires readable_cursor AND equality_comparable>) constexpr bool operator==(basic_proxy_reference_ const & x, basic_proxy_reference_ const & y) { return x.read_() == y.read_(); } template(typename Cur, bool IsReadable)( /// \pre requires readable_cursor AND equality_comparable>) constexpr bool operator!=(basic_proxy_reference_ const & x, basic_proxy_reference_ const & y) { return !(x == y); } template using cpp20_iter_cat_of_t = // std::enable_if_t< // input_cursor, // meta::conditional_t< // contiguous_cursor, // ranges::contiguous_iterator_tag, // meta::conditional_t< // random_access_cursor, // std::random_access_iterator_tag, // meta::conditional_t< // bidirectional_cursor, // std::bidirectional_iterator_tag, // meta::conditional_t< // forward_cursor, // std::forward_iterator_tag, // std::input_iterator_tag>>>>>; // clang-format off template(typename C)( concept (cpp17_input_cursor_)(C), // Either it is not single-pass, or else we can create a // proxy for postfix increment. !range_access::single_pass_t>::value || (move_constructible> && constructible_from, cursor_reference_t>) ); template CPP_concept cpp17_input_cursor = input_cursor && sentinel_for_cursor && CPP_concept_ref(cpp17_input_cursor_, C); template(typename C)( concept (cpp17_forward_cursor_)(C), std::is_reference>::value ); template CPP_concept cpp17_forward_cursor = forward_cursor && CPP_concept_ref(cpp17_forward_cursor_, C); // clang-format on template struct with_iterator_category : Base { using iterator_category = Category; }; template struct with_iterator_category { using iterator_category = Category; }; template using cpp17_iter_cat_of_t = // std::enable_if_t< // cpp17_input_cursor, // meta::conditional_t< // random_access_cursor, // std::random_access_iterator_tag, // meta::conditional_t< // bidirectional_cursor, // std::bidirectional_iterator_tag, // meta::conditional_t< // cpp17_forward_cursor, // std::forward_iterator_tag, // std::input_iterator_tag>>>>; template struct readable_iterator_associated_types_base : range_access::mixin_base_t { readable_iterator_associated_types_base() = default; using range_access::mixin_base_t::mixin_base_t; readable_iterator_associated_types_base(Cur && cur) : range_access::mixin_base_t(static_cast(cur)) {} readable_iterator_associated_types_base(Cur const & cur) : range_access::mixin_base_t(cur) {} }; template struct readable_iterator_associated_types_base< Cur, always_>> : range_access::mixin_base_t { using iterator_category = cpp17_iter_cat_of_t; readable_iterator_associated_types_base() = default; using range_access::mixin_base_t::mixin_base_t; readable_iterator_associated_types_base(Cur && cur) : range_access::mixin_base_t(static_cast(cur)) {} readable_iterator_associated_types_base(Cur const & cur) : range_access::mixin_base_t(cur) {} }; template*/> struct iterator_associated_types_base_ : range_access::mixin_base_t { // BUGBUG // protected: using iter_reference_t = basic_proxy_reference; using const_reference_t = basic_proxy_reference; public: using reference = void; using difference_type = range_access::cursor_difference_t; iterator_associated_types_base_() = default; using range_access::mixin_base_t::mixin_base_t; iterator_associated_types_base_(Cur && cur) : range_access::mixin_base_t(static_cast(cur)) {} iterator_associated_types_base_(Cur const & cur) : range_access::mixin_base_t(cur) {} }; template using cursor_arrow_t = decltype(range_access::arrow(std::declval())); template struct iterator_associated_types_base_ : readable_iterator_associated_types_base { // BUGBUG // protected: using iter_reference_t = meta::conditional_t, basic_proxy_reference, meta::conditional_t, basic_proxy_reference, cursor_reference_t>>; using const_reference_t = meta::conditional_t, basic_proxy_reference, cursor_reference_t>; public: using difference_type = range_access::cursor_difference_t; using value_type = range_access::cursor_value_t; using reference = iter_reference_t; using iterator_concept = cpp20_iter_cat_of_t; using pointer = meta::_t< meta::conditional_t< (bool)has_cursor_arrow, meta::defer, std::add_pointer>>; using common_reference = common_reference_t; iterator_associated_types_base_() = default; using readable_iterator_associated_types_base< Cur>::readable_iterator_associated_types_base; iterator_associated_types_base_(Cur && cur) : readable_iterator_associated_types_base(static_cast(cur)) {} iterator_associated_types_base_(Cur const & cur) : readable_iterator_associated_types_base(cur) {} }; template using iterator_associated_types_base = iterator_associated_types_base_>; template struct postfix_increment_proxy { private: Value cache_; public: template constexpr postfix_increment_proxy(T && t) : cache_(static_cast(t)) {} constexpr Value const & operator*() const noexcept { return cache_; } }; } // namespace detail /// \endcond #if RANGES_BROKEN_CPO_LOOKUP namespace _basic_iterator_ { template struct adl_hook {}; } // namespace _basic_iterator_ #endif template struct RANGES_EMPTY_BASES basic_iterator : detail::iterator_associated_types_base #if RANGES_BROKEN_CPO_LOOKUP , private _basic_iterator_::adl_hook> #endif { private: template friend struct basic_iterator; friend range_access; using base_t = detail::iterator_associated_types_base; using mixin_t = range_access::mixin_base_t; static_assert((bool)detail::cursor, ""); using assoc_types_ = detail::iterator_associated_types_base; using typename assoc_types_::const_reference_t; using typename assoc_types_::iter_reference_t; constexpr Cur & pos() noexcept { return this->mixin_t::basic_mixin::get(); } constexpr Cur const & pos() const noexcept { return this->mixin_t::basic_mixin::get(); } public: using typename assoc_types_::difference_type; constexpr basic_iterator() = default; template(typename OtherCur)( /// \pre requires (!same_as) AND convertible_to AND constructible_from) constexpr basic_iterator(basic_iterator that) : base_t{std::move(that.pos())} {} // Mix in any additional constructors provided by the mixin using base_t::base_t; explicit basic_iterator(Cur && cur) : base_t(static_cast(cur)) {} explicit basic_iterator(Cur const & cur) : base_t(cur) {} template(typename OtherCur)( /// \pre requires (!same_as) AND convertible_to) constexpr basic_iterator & operator=(basic_iterator that) { pos() = std::move(that.pos()); return *this; } CPP_member constexpr auto operator*() const noexcept(noexcept(range_access::read(std::declval()))) -> CPP_ret(const_reference_t)( /// \pre requires detail::readable_cursor && (!detail::is_writable_cursor_v)) { return range_access::read(pos()); } CPP_member constexpr auto operator*() // noexcept(noexcept(iter_reference_t{std::declval()})) // -> CPP_ret(iter_reference_t)( /// \pre requires detail::has_cursor_next && detail::is_writable_cursor_v) { return iter_reference_t{pos()}; } CPP_member constexpr auto operator*() const noexcept(noexcept(const_reference_t{std::declval()})) -> CPP_ret(const_reference_t)( /// \pre requires detail::has_cursor_next && detail::is_writable_cursor_v) { return const_reference_t{pos()}; } CPP_member constexpr auto operator*() noexcept // -> CPP_ret(basic_iterator &)( /// \pre requires (!detail::has_cursor_next)) { return *this; } // Use cursor's arrow() member, if any. template(typename C = Cur)( /// \pre requires detail::has_cursor_arrow) constexpr detail::cursor_arrow_t operator-> () const noexcept(noexcept(range_access::arrow(std::declval()))) { return range_access::arrow(pos()); } // Otherwise, if iter_reference_t is an lvalue reference to cv-qualified // iter_value_t, return the address of **this. template(typename C = Cur)( /// \pre requires (!detail::has_cursor_arrow) AND detail::readable_cursor AND std::is_lvalue_reference::value AND same_as::value_type, uncvref_t>) constexpr std::add_pointer_t operator-> () const noexcept(noexcept(*std::declval())) { return detail::addressof(**this); } CPP_member constexpr auto operator++() // -> CPP_ret(basic_iterator &)( /// \pre requires detail::has_cursor_next) { range_access::next(pos()); return *this; } CPP_member constexpr auto operator++() noexcept // -> CPP_ret(basic_iterator &)( /// \pre requires (!detail::has_cursor_next)) { return *this; } private: constexpr basic_iterator post_increment_(std::false_type, int) { basic_iterator tmp{*this}; ++*this; return tmp; } // Attempt to satisfy the C++17 iterator requirements by returning a // proxy from postfix increment: template(typename A = assoc_types_, typename V = typename A::value_type)( /// \pre requires constructible_from AND move_constructible) constexpr auto post_increment_(std::true_type, int) // -> detail::postfix_increment_proxy { detail::postfix_increment_proxy p{**this}; ++*this; return p; } constexpr void post_increment_(std::true_type, long) { ++*this; } public: CPP_member constexpr auto operator++(int) { return this->post_increment_(meta::bool_ < detail::input_cursor && !detail::forward_cursor> {}, 0); } CPP_member constexpr auto operator--() -> CPP_ret(basic_iterator &)( /// \pre requires detail::bidirectional_cursor) { range_access::prev(pos()); return *this; } CPP_member constexpr auto operator--(int) // -> CPP_ret(basic_iterator)( /// \pre requires detail::bidirectional_cursor) { basic_iterator tmp(*this); --*this; return tmp; } CPP_member constexpr auto operator+=(difference_type n) // -> CPP_ret(basic_iterator &)( /// \pre requires detail::random_access_cursor) { range_access::advance(pos(), n); return *this; } CPP_member constexpr auto operator-=(difference_type n) // -> CPP_ret(basic_iterator &)( /// \pre requires detail::random_access_cursor) { range_access::advance(pos(), (difference_type)-n); return *this; } CPP_member constexpr auto operator[](difference_type n) const // -> CPP_ret(const_reference_t)( /// \pre requires detail::random_access_cursor) { return *(*this + n); } #if !RANGES_BROKEN_CPO_LOOKUP // Optionally support hooking iter_move when the cursor sports a // move() member function. template friend constexpr auto iter_move(basic_iterator const & it) noexcept( noexcept(range_access::move(std::declval()))) -> CPP_broken_friend_ret( decltype(range_access::move(std::declval())))( /// \pre requires same_as && detail::input_cursor) { return range_access::move(it.pos()); } #endif }; template(typename Cur, typename Cur2)( /// \pre requires detail::sentinel_for_cursor) constexpr bool operator==(basic_iterator const & left, basic_iterator const & right) { return range_access::equal(range_access::pos(left), range_access::pos(right)); } template(typename Cur, typename Cur2)( /// \pre requires detail::sentinel_for_cursor) constexpr bool operator!=(basic_iterator const & left, basic_iterator const & right) { return !(left == right); } template(typename Cur, typename S)( /// \pre requires detail::sentinel_for_cursor) constexpr bool operator==(basic_iterator const & left, S const & right) { return range_access::equal(range_access::pos(left), right); } template(typename Cur, typename S)( /// \pre requires detail::sentinel_for_cursor) constexpr bool operator!=(basic_iterator const & left, S const & right) { return !(left == right); } template(typename S, typename Cur)( /// \pre requires detail::sentinel_for_cursor) constexpr bool operator==(S const & left, basic_iterator const & right) { return right == left; } template(typename S, typename Cur)( /// \pre requires detail::sentinel_for_cursor) constexpr bool operator!=(S const & left, basic_iterator const & right) { return right != left; } template(typename Cur)( /// \pre requires detail::random_access_cursor) constexpr basic_iterator // operator+(basic_iterator left, typename basic_iterator::difference_type n) { left += n; return left; } template(typename Cur)( /// \pre requires detail::random_access_cursor) constexpr basic_iterator // operator+(typename basic_iterator::difference_type n, basic_iterator right) { right += n; return right; } template(typename Cur)( /// \pre requires detail::random_access_cursor) constexpr basic_iterator // operator-(basic_iterator left, typename basic_iterator::difference_type n) { left -= n; return left; } template(typename Cur2, typename Cur)( /// \pre requires detail::sized_sentinel_for_cursor) constexpr typename basic_iterator::difference_type // operator-(basic_iterator const & left, basic_iterator const & right) { return range_access::distance_to(range_access::pos(right), range_access::pos(left)); } template(typename S, typename Cur)( /// \pre requires detail::sized_sentinel_for_cursor) constexpr typename basic_iterator::difference_type // operator-(S const & left, basic_iterator const & right) { return range_access::distance_to(range_access::pos(right), left); } template(typename Cur, typename S)( /// \pre requires detail::sized_sentinel_for_cursor) constexpr typename basic_iterator::difference_type // operator-(basic_iterator const & left, S const & right) { return -(right - left); } // Asymmetric comparisons template(typename Left, typename Right)( /// \pre requires detail::sized_sentinel_for_cursor) constexpr bool operator<(basic_iterator const & left, basic_iterator const & right) { return 0 < (right - left); } template(typename Left, typename Right)( /// \pre requires detail::sized_sentinel_for_cursor) constexpr bool operator<=(basic_iterator const & left, basic_iterator const & right) { return 0 <= (right - left); } template(typename Left, typename Right)( /// \pre requires detail::sized_sentinel_for_cursor) constexpr bool operator>(basic_iterator const & left, basic_iterator const & right) { return (right - left) < 0; } template(typename Left, typename Right)( /// \pre requires detail::sized_sentinel_for_cursor) constexpr bool operator>=(basic_iterator const & left, basic_iterator const & right) { return (right - left) <= 0; } #if RANGES_BROKEN_CPO_LOOKUP namespace _basic_iterator_ { // Optionally support hooking iter_move when the cursor sports a // move() member function. template constexpr auto iter_move(basic_iterator const & it) noexcept( noexcept(range_access::move(std::declval()))) -> CPP_broken_friend_ret( decltype(range_access::move(std::declval())))( /// \pre requires detail::input_cursor) { return range_access::move(range_access::pos(it)); } } // namespace _basic_iterator_ #endif /// Get a cursor from a basic_iterator struct get_cursor_fn { template constexpr Cur & operator()(basic_iterator & it) const noexcept { return range_access::pos(it); } template constexpr Cur const & operator()(basic_iterator const & it) const noexcept { return range_access::pos(it); } template constexpr Cur operator()(basic_iterator && it) const noexcept(std::is_nothrow_move_constructible::value) { return range_access::pos(std::move(it)); } }; /// \sa `get_cursor_fn` RANGES_INLINE_VARIABLE(get_cursor_fn, get_cursor) /// @} } // namespace ranges /// \cond namespace concepts { // common_reference specializations for basic_proxy_reference template class TQual, template class UQual> struct basic_common_reference<::ranges::detail::basic_proxy_reference_, U, TQual, UQual> : basic_common_reference<::ranges::detail::cursor_reference_t, U, TQual, UQual> {}; template class TQual, template class UQual> struct basic_common_reference, TQual, UQual> : basic_common_reference, TQual, UQual> {}; template class TQual, template class UQual> struct basic_common_reference<::ranges::detail::basic_proxy_reference_, ::ranges::detail::basic_proxy_reference_, TQual, UQual> : basic_common_reference<::ranges::detail::cursor_reference_t, ::ranges::detail::cursor_reference_t, TQual, UQual> {}; // common_type specializations for basic_proxy_reference template struct common_type<::ranges::detail::basic_proxy_reference_, U> : common_type<::ranges::range_access::cursor_value_t, U> {}; template struct common_type> : common_type> {}; template struct common_type<::ranges::detail::basic_proxy_reference_, ::ranges::detail::basic_proxy_reference_> : common_type<::ranges::range_access::cursor_value_t, ::ranges::range_access::cursor_value_t> {}; } // namespace concepts #if RANGES_CXX_VER > RANGES_CXX_STD_17 RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS RANGES_BEGIN_NAMESPACE_STD RANGES_BEGIN_NAMESPACE_VERSION template class, template class> struct basic_common_reference; // common_reference specializations for basic_proxy_reference template class TQual, template class UQual> struct basic_common_reference<::ranges::detail::basic_proxy_reference_, U, TQual, UQual> : basic_common_reference<::ranges::detail::cursor_reference_t, U, TQual, UQual> {}; template class TQual, template class UQual> struct basic_common_reference, TQual, UQual> : basic_common_reference, TQual, UQual> {}; template class TQual, template class UQual> struct basic_common_reference<::ranges::detail::basic_proxy_reference_, ::ranges::detail::basic_proxy_reference_, TQual, UQual> : basic_common_reference<::ranges::detail::cursor_reference_t, ::ranges::detail::cursor_reference_t, TQual, UQual> {}; template struct common_type; // common_type specializations for basic_proxy_reference template struct common_type<::ranges::detail::basic_proxy_reference_, U> : common_type<::ranges::range_access::cursor_value_t, U> {}; template struct common_type> : common_type> {}; template struct common_type<::ranges::detail::basic_proxy_reference_, ::ranges::detail::basic_proxy_reference_> : common_type<::ranges::range_access::cursor_value_t, ::ranges::range_access::cursor_value_t> {}; RANGES_END_NAMESPACE_VERSION RANGES_END_NAMESPACE_STD RANGES_DIAGNOSTIC_POP #endif // RANGES_CXX_VER > RANGES_CXX_STD_17 namespace ranges { /// \cond namespace detail { template struct std_iterator_traits_ { using difference_type = typename iterator_associated_types_base::difference_type; using value_type = void; using reference = void; using pointer = void; using iterator_category = std::output_iterator_tag; using iterator_concept = std::output_iterator_tag; }; template struct std_iterator_traits_ : iterator_associated_types_base {}; template using std_iterator_traits = std_iterator_traits_>; } // namespace detail /// \endcond } // namespace ranges namespace std { template struct iterator_traits<::ranges::basic_iterator> : ::ranges::detail::std_iterator_traits {}; } // namespace std /// \endcond RANGES_DIAGNOSTIC_POP #include #endif