Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-03 08:13:53

0001 // -*- C++ -*-
0002 //===----------------------------------------------------------------------===//
0003 //
0004 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0005 // See https://llvm.org/LICENSE.txt for license information.
0006 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0007 //
0008 //===----------------------------------------------------------------------===//
0009 
0010 #ifndef _LIBCPP___ITERATOR_ITERATOR_TRAITS_H
0011 #define _LIBCPP___ITERATOR_ITERATOR_TRAITS_H
0012 
0013 #include <__concepts/arithmetic.h>
0014 #include <__concepts/constructible.h>
0015 #include <__concepts/convertible_to.h>
0016 #include <__concepts/copyable.h>
0017 #include <__concepts/equality_comparable.h>
0018 #include <__concepts/same_as.h>
0019 #include <__concepts/totally_ordered.h>
0020 #include <__config>
0021 #include <__cstddef/ptrdiff_t.h>
0022 #include <__fwd/pair.h>
0023 #include <__iterator/incrementable_traits.h>
0024 #include <__iterator/readable_traits.h>
0025 #include <__type_traits/common_reference.h>
0026 #include <__type_traits/conditional.h>
0027 #include <__type_traits/disjunction.h>
0028 #include <__type_traits/enable_if.h>
0029 #include <__type_traits/integral_constant.h>
0030 #include <__type_traits/is_convertible.h>
0031 #include <__type_traits/is_object.h>
0032 #include <__type_traits/is_primary_template.h>
0033 #include <__type_traits/is_reference.h>
0034 #include <__type_traits/is_valid_expansion.h>
0035 #include <__type_traits/remove_const.h>
0036 #include <__type_traits/remove_cv.h>
0037 #include <__type_traits/remove_cvref.h>
0038 #include <__type_traits/void_t.h>
0039 #include <__utility/declval.h>
0040 
0041 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0042 #  pragma GCC system_header
0043 #endif
0044 
0045 _LIBCPP_BEGIN_NAMESPACE_STD
0046 
0047 #if _LIBCPP_STD_VER >= 20
0048 
0049 template <class _Tp>
0050 using __with_reference _LIBCPP_NODEBUG = _Tp&;
0051 
0052 template <class _Tp>
0053 concept __can_reference = requires { typename __with_reference<_Tp>; };
0054 
0055 template <class _Tp>
0056 concept __dereferenceable = requires(_Tp& __t) {
0057   { *__t } -> __can_reference; // not required to be equality-preserving
0058 };
0059 
0060 // [iterator.traits]
0061 template <__dereferenceable _Tp>
0062 using iter_reference_t = decltype(*std::declval<_Tp&>());
0063 
0064 #endif // _LIBCPP_STD_VER >= 20
0065 
0066 template <class _Iter>
0067 struct _LIBCPP_TEMPLATE_VIS iterator_traits;
0068 
0069 struct _LIBCPP_TEMPLATE_VIS input_iterator_tag {};
0070 struct _LIBCPP_TEMPLATE_VIS output_iterator_tag {};
0071 struct _LIBCPP_TEMPLATE_VIS forward_iterator_tag : public input_iterator_tag {};
0072 struct _LIBCPP_TEMPLATE_VIS bidirectional_iterator_tag : public forward_iterator_tag {};
0073 struct _LIBCPP_TEMPLATE_VIS random_access_iterator_tag : public bidirectional_iterator_tag {};
0074 #if _LIBCPP_STD_VER >= 20
0075 struct _LIBCPP_TEMPLATE_VIS contiguous_iterator_tag : public random_access_iterator_tag {};
0076 #endif
0077 
0078 template <class _Iter>
0079 struct __iter_traits_cache {
0080   using type = _If< __is_primary_template<iterator_traits<_Iter> >::value, _Iter, iterator_traits<_Iter> >;
0081 };
0082 template <class _Iter>
0083 using _ITER_TRAITS _LIBCPP_NODEBUG = typename __iter_traits_cache<_Iter>::type;
0084 
0085 struct __iter_concept_concept_test {
0086   template <class _Iter>
0087   using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_concept;
0088 };
0089 struct __iter_concept_category_test {
0090   template <class _Iter>
0091   using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_category;
0092 };
0093 struct __iter_concept_random_fallback {
0094   template <class _Iter>
0095   using _Apply _LIBCPP_NODEBUG =
0096       __enable_if_t<__is_primary_template<iterator_traits<_Iter> >::value, random_access_iterator_tag>;
0097 };
0098 
0099 template <class _Iter, class _Tester>
0100 struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>, _Tester {};
0101 
0102 template <class _Iter>
0103 struct __iter_concept_cache {
0104   using type = _Or< __test_iter_concept<_Iter, __iter_concept_concept_test>,
0105                     __test_iter_concept<_Iter, __iter_concept_category_test>,
0106                     __test_iter_concept<_Iter, __iter_concept_random_fallback> >;
0107 };
0108 
0109 template <class _Iter>
0110 using _ITER_CONCEPT _LIBCPP_NODEBUG = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>;
0111 
0112 template <class _Tp>
0113 struct __has_iterator_typedefs {
0114 private:
0115   template <class _Up>
0116   static false_type __test(...);
0117   template <class _Up>
0118   static true_type
0119   __test(__void_t<typename _Up::iterator_category>* = nullptr,
0120          __void_t<typename _Up::difference_type>*   = nullptr,
0121          __void_t<typename _Up::value_type>*        = nullptr,
0122          __void_t<typename _Up::reference>*         = nullptr,
0123          __void_t<typename _Up::pointer>*           = nullptr);
0124 
0125 public:
0126   static const bool value = decltype(__test<_Tp>(nullptr, nullptr, nullptr, nullptr, nullptr))::value;
0127 };
0128 
0129 template <class _Tp>
0130 struct __has_iterator_category {
0131 private:
0132   template <class _Up>
0133   static false_type __test(...);
0134   template <class _Up>
0135   static true_type __test(typename _Up::iterator_category* = nullptr);
0136 
0137 public:
0138   static const bool value = decltype(__test<_Tp>(nullptr))::value;
0139 };
0140 
0141 template <class _Tp>
0142 struct __has_iterator_concept {
0143 private:
0144   template <class _Up>
0145   static false_type __test(...);
0146   template <class _Up>
0147   static true_type __test(typename _Up::iterator_concept* = nullptr);
0148 
0149 public:
0150   static const bool value = decltype(__test<_Tp>(nullptr))::value;
0151 };
0152 
0153 #if _LIBCPP_STD_VER >= 20
0154 
0155 // The `cpp17-*-iterator` exposition-only concepts have very similar names to the `Cpp17*Iterator` named requirements
0156 // from `[iterator.cpp17]`. To avoid confusion between the two, the exposition-only concepts have been banished to
0157 // a "detail" namespace indicating they have a niche use-case.
0158 namespace __iterator_traits_detail {
0159 template <class _Ip>
0160 concept __cpp17_iterator = requires(_Ip __i) {
0161   { *__i } -> __can_reference;
0162   { ++__i } -> same_as<_Ip&>;
0163   { *__i++ } -> __can_reference;
0164 } && copyable<_Ip>;
0165 
0166 template <class _Ip>
0167 concept __cpp17_input_iterator = __cpp17_iterator<_Ip> && equality_comparable<_Ip> && requires(_Ip __i) {
0168   typename incrementable_traits<_Ip>::difference_type;
0169   typename indirectly_readable_traits<_Ip>::value_type;
0170   typename common_reference_t<iter_reference_t<_Ip>&&, typename indirectly_readable_traits<_Ip>::value_type&>;
0171   typename common_reference_t<decltype(*__i++)&&, typename indirectly_readable_traits<_Ip>::value_type&>;
0172   requires signed_integral<typename incrementable_traits<_Ip>::difference_type>;
0173 };
0174 
0175 template <class _Ip>
0176 concept __cpp17_forward_iterator =
0177     __cpp17_input_iterator<_Ip> && constructible_from<_Ip> && is_reference_v<iter_reference_t<_Ip>> &&
0178     same_as<remove_cvref_t<iter_reference_t<_Ip>>, typename indirectly_readable_traits<_Ip>::value_type> &&
0179     requires(_Ip __i) {
0180       { __i++ } -> convertible_to<_Ip const&>;
0181       { *__i++ } -> same_as<iter_reference_t<_Ip>>;
0182     };
0183 
0184 template <class _Ip>
0185 concept __cpp17_bidirectional_iterator = __cpp17_forward_iterator<_Ip> && requires(_Ip __i) {
0186   { --__i } -> same_as<_Ip&>;
0187   { __i-- } -> convertible_to<_Ip const&>;
0188   { *__i-- } -> same_as<iter_reference_t<_Ip>>;
0189 };
0190 
0191 template <class _Ip>
0192 concept __cpp17_random_access_iterator =
0193     __cpp17_bidirectional_iterator<_Ip> && totally_ordered<_Ip> &&
0194     requires(_Ip __i, typename incrementable_traits<_Ip>::difference_type __n) {
0195       { __i += __n } -> same_as<_Ip&>;
0196       { __i -= __n } -> same_as<_Ip&>;
0197       { __i + __n } -> same_as<_Ip>;
0198       { __n + __i } -> same_as<_Ip>;
0199       { __i - __n } -> same_as<_Ip>;
0200       { __i - __i } -> same_as<decltype(__n)>; // NOLINT(misc-redundant-expression) ; This is llvm.org/PR54114
0201       { __i[__n] } -> convertible_to<iter_reference_t<_Ip>>;
0202     };
0203 } // namespace __iterator_traits_detail
0204 
0205 template <class _Ip>
0206 concept __has_member_reference = requires { typename _Ip::reference; };
0207 
0208 template <class _Ip>
0209 concept __has_member_pointer = requires { typename _Ip::pointer; };
0210 
0211 template <class _Ip>
0212 concept __has_member_iterator_category = requires { typename _Ip::iterator_category; };
0213 
0214 template <class _Ip>
0215 concept __specifies_members = requires {
0216   typename _Ip::value_type;
0217   typename _Ip::difference_type;
0218   requires __has_member_reference<_Ip>;
0219   requires __has_member_iterator_category<_Ip>;
0220 };
0221 
0222 template <class>
0223 struct __iterator_traits_member_pointer_or_void {
0224   using type = void;
0225 };
0226 
0227 template <__has_member_pointer _Tp>
0228 struct __iterator_traits_member_pointer_or_void<_Tp> {
0229   using type = typename _Tp::pointer;
0230 };
0231 
0232 template <class _Tp>
0233 concept __cpp17_iterator_missing_members = !__specifies_members<_Tp> && __iterator_traits_detail::__cpp17_iterator<_Tp>;
0234 
0235 template <class _Tp>
0236 concept __cpp17_input_iterator_missing_members =
0237     __cpp17_iterator_missing_members<_Tp> && __iterator_traits_detail::__cpp17_input_iterator<_Tp>;
0238 
0239 // Otherwise, `pointer` names `void`.
0240 template <class>
0241 struct __iterator_traits_member_pointer_or_arrow_or_void {
0242   using type = void;
0243 };
0244 
0245 // [iterator.traits]/3.2.1
0246 // If the qualified-id `I::pointer` is valid and denotes a type, `pointer` names that type.
0247 template <__has_member_pointer _Ip>
0248 struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> {
0249   using type = typename _Ip::pointer;
0250 };
0251 
0252 // Otherwise, if `decltype(declval<I&>().operator->())` is well-formed, then `pointer` names that
0253 // type.
0254 template <class _Ip>
0255   requires requires(_Ip& __i) { __i.operator->(); } && (!__has_member_pointer<_Ip>)
0256 struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> {
0257   using type = decltype(std::declval<_Ip&>().operator->());
0258 };
0259 
0260 // Otherwise, `reference` names `iter-reference-t<I>`.
0261 template <class _Ip>
0262 struct __iterator_traits_member_reference {
0263   using type = iter_reference_t<_Ip>;
0264 };
0265 
0266 // [iterator.traits]/3.2.2
0267 // If the qualified-id `I::reference` is valid and denotes a type, `reference` names that type.
0268 template <__has_member_reference _Ip>
0269 struct __iterator_traits_member_reference<_Ip> {
0270   using type = typename _Ip::reference;
0271 };
0272 
0273 // [iterator.traits]/3.2.3.4
0274 // input_iterator_tag
0275 template <class _Ip>
0276 struct __deduce_iterator_category {
0277   using type = input_iterator_tag;
0278 };
0279 
0280 // [iterator.traits]/3.2.3.1
0281 // `random_access_iterator_tag` if `I` satisfies `cpp17-random-access-iterator`, or otherwise
0282 template <__iterator_traits_detail::__cpp17_random_access_iterator _Ip>
0283 struct __deduce_iterator_category<_Ip> {
0284   using type = random_access_iterator_tag;
0285 };
0286 
0287 // [iterator.traits]/3.2.3.2
0288 // `bidirectional_iterator_tag` if `I` satisfies `cpp17-bidirectional-iterator`, or otherwise
0289 template <__iterator_traits_detail::__cpp17_bidirectional_iterator _Ip>
0290 struct __deduce_iterator_category<_Ip> {
0291   using type = bidirectional_iterator_tag;
0292 };
0293 
0294 // [iterator.traits]/3.2.3.3
0295 // `forward_iterator_tag` if `I` satisfies `cpp17-forward-iterator`, or otherwise
0296 template <__iterator_traits_detail::__cpp17_forward_iterator _Ip>
0297 struct __deduce_iterator_category<_Ip> {
0298   using type = forward_iterator_tag;
0299 };
0300 
0301 template <class _Ip>
0302 struct __iterator_traits_iterator_category : __deduce_iterator_category<_Ip> {};
0303 
0304 // [iterator.traits]/3.2.3
0305 // If the qualified-id `I::iterator-category` is valid and denotes a type, `iterator-category` names
0306 // that type.
0307 template <__has_member_iterator_category _Ip>
0308 struct __iterator_traits_iterator_category<_Ip> {
0309   using type = typename _Ip::iterator_category;
0310 };
0311 
0312 // otherwise, it names void.
0313 template <class>
0314 struct __iterator_traits_difference_type {
0315   using type = void;
0316 };
0317 
0318 // If the qualified-id `incrementable_traits<I>::difference_type` is valid and denotes a type, then
0319 // `difference_type` names that type;
0320 template <class _Ip>
0321   requires requires { typename incrementable_traits<_Ip>::difference_type; }
0322 struct __iterator_traits_difference_type<_Ip> {
0323   using type = typename incrementable_traits<_Ip>::difference_type;
0324 };
0325 
0326 // [iterator.traits]/3.4
0327 // Otherwise, `iterator_traits<I>` has no members by any of the above names.
0328 template <class>
0329 struct __iterator_traits {};
0330 
0331 // [iterator.traits]/3.1
0332 // If `I` has valid ([temp.deduct]) member types `difference-type`, `value-type`, `reference`, and
0333 // `iterator-category`, then `iterator-traits<I>` has the following publicly accessible members:
0334 template <__specifies_members _Ip>
0335 struct __iterator_traits<_Ip> {
0336   using iterator_category = typename _Ip::iterator_category;
0337   using value_type        = typename _Ip::value_type;
0338   using difference_type   = typename _Ip::difference_type;
0339   using pointer           = typename __iterator_traits_member_pointer_or_void<_Ip>::type;
0340   using reference         = typename _Ip::reference;
0341 };
0342 
0343 // [iterator.traits]/3.2
0344 // Otherwise, if `I` satisfies the exposition-only concept `cpp17-input-iterator`,
0345 // `iterator-traits<I>` has the following publicly accessible members:
0346 template <__cpp17_input_iterator_missing_members _Ip>
0347 struct __iterator_traits<_Ip> {
0348   using iterator_category = typename __iterator_traits_iterator_category<_Ip>::type;
0349   using value_type        = typename indirectly_readable_traits<_Ip>::value_type;
0350   using difference_type   = typename incrementable_traits<_Ip>::difference_type;
0351   using pointer           = typename __iterator_traits_member_pointer_or_arrow_or_void<_Ip>::type;
0352   using reference         = typename __iterator_traits_member_reference<_Ip>::type;
0353 };
0354 
0355 // Otherwise, if `I` satisfies the exposition-only concept `cpp17-iterator`, then
0356 // `iterator_traits<I>` has the following publicly accessible members:
0357 template <__cpp17_iterator_missing_members _Ip>
0358 struct __iterator_traits<_Ip> {
0359   using iterator_category = output_iterator_tag;
0360   using value_type        = void;
0361   using difference_type   = typename __iterator_traits_difference_type<_Ip>::type;
0362   using pointer           = void;
0363   using reference         = void;
0364 };
0365 
0366 template <class _Ip>
0367 struct iterator_traits : __iterator_traits<_Ip> {
0368   using __primary_template _LIBCPP_NODEBUG = iterator_traits;
0369 };
0370 
0371 #else  // _LIBCPP_STD_VER >= 20
0372 
0373 template <class _Iter, bool>
0374 struct __iterator_traits {};
0375 
0376 template <class _Iter, bool>
0377 struct __iterator_traits_impl {};
0378 
0379 template <class _Iter>
0380 struct __iterator_traits_impl<_Iter, true> {
0381   typedef typename _Iter::difference_type difference_type;
0382   typedef typename _Iter::value_type value_type;
0383   typedef typename _Iter::pointer pointer;
0384   typedef typename _Iter::reference reference;
0385   typedef typename _Iter::iterator_category iterator_category;
0386 };
0387 
0388 template <class _Iter>
0389 struct __iterator_traits<_Iter, true>
0390     : __iterator_traits_impl< _Iter,
0391                               is_convertible<typename _Iter::iterator_category, input_iterator_tag>::value ||
0392                                   is_convertible<typename _Iter::iterator_category, output_iterator_tag>::value > {};
0393 
0394 // iterator_traits<Iterator> will only have the nested types if Iterator::iterator_category
0395 //    exists.  Else iterator_traits<Iterator> will be an empty class.  This is a
0396 //    conforming extension which allows some programs to compile and behave as
0397 //    the client expects instead of failing at compile time.
0398 
0399 template <class _Iter>
0400 struct _LIBCPP_TEMPLATE_VIS iterator_traits : __iterator_traits<_Iter, __has_iterator_typedefs<_Iter>::value> {
0401   using __primary_template _LIBCPP_NODEBUG = iterator_traits;
0402 };
0403 #endif // _LIBCPP_STD_VER >= 20
0404 
0405 template <class _Tp>
0406 #if _LIBCPP_STD_VER >= 20
0407   requires is_object_v<_Tp>
0408 #endif
0409 struct _LIBCPP_TEMPLATE_VIS iterator_traits<_Tp*> {
0410   typedef ptrdiff_t difference_type;
0411   typedef __remove_cv_t<_Tp> value_type;
0412   typedef _Tp* pointer;
0413   typedef _Tp& reference;
0414   typedef random_access_iterator_tag iterator_category;
0415 #if _LIBCPP_STD_VER >= 20
0416   typedef contiguous_iterator_tag iterator_concept;
0417 #endif
0418 };
0419 
0420 template <class _Tp, class _Up, bool = __has_iterator_category<iterator_traits<_Tp> >::value>
0421 struct __has_iterator_category_convertible_to : is_convertible<typename iterator_traits<_Tp>::iterator_category, _Up> {
0422 };
0423 
0424 template <class _Tp, class _Up>
0425 struct __has_iterator_category_convertible_to<_Tp, _Up, false> : false_type {};
0426 
0427 template <class _Tp, class _Up, bool = __has_iterator_concept<_Tp>::value>
0428 struct __has_iterator_concept_convertible_to : is_convertible<typename _Tp::iterator_concept, _Up> {};
0429 
0430 template <class _Tp, class _Up>
0431 struct __has_iterator_concept_convertible_to<_Tp, _Up, false> : false_type {};
0432 
0433 template <class _Tp>
0434 using __has_input_iterator_category _LIBCPP_NODEBUG = __has_iterator_category_convertible_to<_Tp, input_iterator_tag>;
0435 
0436 template <class _Tp>
0437 using __has_forward_iterator_category _LIBCPP_NODEBUG =
0438     __has_iterator_category_convertible_to<_Tp, forward_iterator_tag>;
0439 
0440 template <class _Tp>
0441 using __has_bidirectional_iterator_category _LIBCPP_NODEBUG =
0442     __has_iterator_category_convertible_to<_Tp, bidirectional_iterator_tag>;
0443 
0444 template <class _Tp>
0445 using __has_random_access_iterator_category _LIBCPP_NODEBUG =
0446     __has_iterator_category_convertible_to<_Tp, random_access_iterator_tag>;
0447 
0448 // __libcpp_is_contiguous_iterator determines if an iterator is known by
0449 // libc++ to be contiguous, either because it advertises itself as such
0450 // (in C++20) or because it is a pointer type or a known trivial wrapper
0451 // around a (possibly fancy) pointer type, such as __wrap_iter<T*>.
0452 // Such iterators receive special "contiguous" optimizations in
0453 // std::copy and std::sort.
0454 //
0455 #if _LIBCPP_STD_VER >= 20
0456 template <class _Tp>
0457 struct __libcpp_is_contiguous_iterator
0458     : _Or< __has_iterator_category_convertible_to<_Tp, contiguous_iterator_tag>,
0459            __has_iterator_concept_convertible_to<_Tp, contiguous_iterator_tag> > {};
0460 #else
0461 template <class _Tp>
0462 struct __libcpp_is_contiguous_iterator : false_type {};
0463 #endif
0464 
0465 // Any native pointer which is an iterator is also a contiguous iterator.
0466 template <class _Up>
0467 struct __libcpp_is_contiguous_iterator<_Up*> : true_type {};
0468 
0469 template <class _Iter>
0470 class __wrap_iter;
0471 
0472 template <class _Tp>
0473 using __has_exactly_input_iterator_category _LIBCPP_NODEBUG =
0474     integral_constant<bool,
0475                       __has_iterator_category_convertible_to<_Tp, input_iterator_tag>::value &&
0476                           !__has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value>;
0477 
0478 template <class _Tp>
0479 using __has_exactly_forward_iterator_category _LIBCPP_NODEBUG =
0480     integral_constant<bool,
0481                       __has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value &&
0482                           !__has_iterator_category_convertible_to<_Tp, bidirectional_iterator_tag>::value>;
0483 
0484 template <class _Tp>
0485 using __has_exactly_bidirectional_iterator_category _LIBCPP_NODEBUG =
0486     integral_constant<bool,
0487                       __has_iterator_category_convertible_to<_Tp, bidirectional_iterator_tag>::value &&
0488                           !__has_iterator_category_convertible_to<_Tp, random_access_iterator_tag>::value>;
0489 
0490 template <class _InputIterator>
0491 using __iter_value_type _LIBCPP_NODEBUG = typename iterator_traits<_InputIterator>::value_type;
0492 
0493 template <class _InputIterator>
0494 using __iter_key_type _LIBCPP_NODEBUG =
0495     __remove_const_t<typename iterator_traits<_InputIterator>::value_type::first_type>;
0496 
0497 template <class _InputIterator>
0498 using __iter_mapped_type _LIBCPP_NODEBUG = typename iterator_traits<_InputIterator>::value_type::second_type;
0499 
0500 template <class _InputIterator>
0501 using __iter_to_alloc_type _LIBCPP_NODEBUG =
0502     pair<const typename iterator_traits<_InputIterator>::value_type::first_type,
0503          typename iterator_traits<_InputIterator>::value_type::second_type>;
0504 
0505 template <class _Iter>
0506 using __iterator_category_type _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::iterator_category;
0507 
0508 template <class _Iter>
0509 using __iterator_pointer_type _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::pointer;
0510 
0511 template <class _Iter>
0512 using __iter_diff_t _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::difference_type;
0513 
0514 template <class _Iter>
0515 using __iter_reference _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::reference;
0516 
0517 #if _LIBCPP_STD_VER >= 20
0518 
0519 // [readable.traits]
0520 
0521 // Let `RI` be `remove_cvref_t<I>`. The type `iter_value_t<I>` denotes
0522 // `indirectly_readable_traits<RI>::value_type` if `iterator_traits<RI>` names a specialization
0523 // generated from the primary template, and `iterator_traits<RI>::value_type` otherwise.
0524 // This has to be in this file and not readable_traits.h to break the include cycle between the two.
0525 template <class _Ip>
0526 using iter_value_t =
0527     typename conditional_t<__is_primary_template<iterator_traits<remove_cvref_t<_Ip> > >::value,
0528                            indirectly_readable_traits<remove_cvref_t<_Ip> >,
0529                            iterator_traits<remove_cvref_t<_Ip> > >::value_type;
0530 
0531 #endif // _LIBCPP_STD_VER >= 20
0532 
0533 _LIBCPP_END_NAMESPACE_STD
0534 
0535 #endif // _LIBCPP___ITERATOR_ITERATOR_TRAITS_H