Skip to content

Commit 0e4c641

Browse files
authored
Allow both ::value_type and ::element_type in indirectly_readable_traits (#834)
Per [readable.traits], `indirectly_readable_traits<T>::value_type` is the same type as `remove_cv_t<T::value_type>` if it denotes an object type, or `remove_cv_t<T::element_type>` if it denotes an object type. If both `T::value_type` and `T::element_type` denote types, `indirectly_readable_traits<T>::value_type` is ill-formed. This was perhaps not the best design, given that there are iterators in the wild (Boost's unordered containers) that define both nested types. `indirectly_readable_traits` should tolerate iterators that define both nested types consistently. Fixes VSO-1121031.
1 parent e76f500 commit 0e4c641

2 files changed

Lines changed: 28 additions & 0 deletions

File tree

stl/inc/xutility

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,13 @@ struct indirectly_readable_traits<_Ty> : _Cond_value_type<typename _Ty::value_ty
377377
template <_Has_member_element_type _Ty>
378378
struct indirectly_readable_traits<_Ty> : _Cond_value_type<typename _Ty::element_type> {};
379379

380+
// clang-format off
381+
template <_Has_member_value_type _Ty> // Per LWG issue submitted but unnumbered as of 2020-05-14
382+
requires _Has_member_element_type<_Ty>
383+
&& same_as<remove_cv_t<typename _Ty::value_type>, remove_cv_t<typename _Ty::element_type>>
384+
struct indirectly_readable_traits<_Ty> : _Cond_value_type<typename _Ty::value_type> {};
385+
// clang-format on
386+
380387
// ALIAS TEMPLATE iter_value_t
381388
template <class _Ty>
382389
using iter_value_t = typename conditional_t<_Is_from_primary<iterator_traits<remove_cvref_t<_Ty>>>,

tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3239,6 +3239,27 @@ namespace lwg3420 {
32393239
STATIC_ASSERT(!has_member_value_type<std::iterator_traits<X>>);
32403240
} // namespace lwg3420
32413241

3242+
namespace vso1121031 {
3243+
// Validate that indirectly_readable_traits accepts type arguments with both value_type and element_type nested
3244+
// types if they are consistent.
3245+
using std::indirectly_readable_traits, std::same_as;
3246+
3247+
template <class Element>
3248+
struct iterish {
3249+
using value_type = int;
3250+
using element_type = Element;
3251+
};
3252+
STATIC_ASSERT(same_as<indirectly_readable_traits<iterish<int>>::value_type, int>);
3253+
STATIC_ASSERT(same_as<indirectly_readable_traits<iterish<int const>>::value_type, int>);
3254+
STATIC_ASSERT(same_as<indirectly_readable_traits<iterish<int volatile>>::value_type, int>);
3255+
STATIC_ASSERT(same_as<indirectly_readable_traits<iterish<int const volatile>>::value_type, int>);
3256+
3257+
STATIC_ASSERT(!has_member_value_type<indirectly_readable_traits<iterish<float>>>);
3258+
STATIC_ASSERT(!has_member_value_type<indirectly_readable_traits<iterish<float const>>>);
3259+
STATIC_ASSERT(!has_member_value_type<indirectly_readable_traits<iterish<float volatile>>>);
3260+
STATIC_ASSERT(!has_member_value_type<indirectly_readable_traits<iterish<float const volatile>>>);
3261+
} // namespace vso1121031
3262+
32423263
int main() {
32433264
iterator_cust_swap_test::test();
32443265
iter_ops::test();

0 commit comments

Comments
 (0)