diff --git a/stl/inc/concepts b/stl/inc/concepts index 2cc8f904bad..4da6a23f497 100644 --- a/stl/inc/concepts +++ b/stl/inc/concepts @@ -79,7 +79,7 @@ concept integral = is_integral_v<_Ty>; // CONCEPT signed_integral template -concept signed_integral = integral<_Ty> && _Ty(-1) < _Ty(0); +concept signed_integral = integral<_Ty> && static_cast<_Ty>(-1) < static_cast<_Ty>(0); // CONCEPT unsigned_integral template diff --git a/stl/inc/type_traits b/stl/inc/type_traits index e17f1b7381c..48ec61ed301 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -905,7 +905,7 @@ template > struct _Sign_base { // determine whether integral type _Ty is signed or unsigned using _Uty = remove_cv_t<_Ty>; - static constexpr bool _Signed = _Uty(-1) < _Uty(0); + static constexpr bool _Signed = static_cast<_Uty>(-1) < static_cast<_Uty>(0); static constexpr bool _Unsigned = !_Signed; }; diff --git a/stl/inc/xutility b/stl/inc/xutility index f80ed07fa86..71dec8d8fad 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -741,20 +741,34 @@ concept indirectly_writable = requires(_It&& __i, _Ty&& __t) { const_cast&&>(*static_cast<_It&&>(__i)) = static_cast<_Ty&&>(__t); }; +// CONCEPT _Integer_like +// clang-format off +template +concept _Integer_like = _Is_nonbool_integral<_Ty>; // per the proposed resolution of LWG-3467 + +// CONCEPT _Signed_integer_like +template +concept _Signed_integer_like = _Integer_like<_Ty> && static_cast<_Ty>(-1) < static_cast<_Ty>(0); +// clang-format on + +// ALIAS TEMPLATE _Make_unsigned_like_t +template +using _Make_unsigned_like_t = make_unsigned_t<_Ty>; + +// ALIAS TEMPLATE _Make_signed_like_t +template +using _Make_signed_like_t = make_signed_t<_Ty>; // per the proposed resolution of LWG-3403 + // CONCEPT weakly_incrementable // clang-format off template concept weakly_incrementable = default_initializable<_Ty> && movable<_Ty> && requires(_Ty __i) { typename iter_difference_t<_Ty>; - requires signed_integral>; + requires _Signed_integer_like>; { ++__i } -> same_as<_Ty&>; __i++; }; -// ALIAS TEMPLATE _Make_unsigned_like_t -template -using _Make_unsigned_like_t = make_unsigned_t<_Ty>; - // CONCEPT incrementable template concept incrementable = regular<_Ty> && weakly_incrementable<_Ty> && requires(_Ty __t) { @@ -2831,12 +2845,12 @@ namespace ranges { // clang-format off template concept _Has_member = !disable_sized_range<_UnCV> && requires(_Ty __t) { - { _Fake_decay_copy(__t.size()) } -> integral; + { _Fake_decay_copy(__t.size()) } -> _Integer_like; }; template concept _Has_ADL = _Has_class_or_enum_type<_Ty> && !disable_sized_range<_UnCV> && requires(_Ty __t) { - { _Fake_decay_copy(size(__t)) } -> integral; + { _Fake_decay_copy(size(__t)) } -> _Integer_like; }; template @@ -3121,7 +3135,7 @@ namespace ranges { ~_Not_quite_object() = default; }; - // CLASS ranges::_Advance_fn + // VARIABLE ranges::advance class _Advance_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -3211,10 +3225,9 @@ namespace ranges { } }; - // VARIABLE ranges::advance inline constexpr _Advance_fn advance{_Not_quite_object::_Construct_tag{}}; - // CLASS ranges::_Distance_fn + // VARIABLE ranges::distance class _Distance_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -3246,10 +3259,26 @@ namespace ranges { } }; - // VARIABLE ranges::distance inline constexpr _Distance_fn distance{_Not_quite_object::_Construct_tag{}}; - // CLASS ranges::_Next_fn + // VARIABLE ranges::ssize + class _Ssize_fn { // Per the proposed resolution of LWG-3403 + public: + // clang-format off + template + _NODISCARD constexpr auto operator()(_Rng&& _Range) const requires requires { _RANGES size(_Range); } { + using _Sty = _Make_signed_like_t; + using _Ty = common_type_t, ptrdiff_t, _Sty>, _Sty>; + return static_cast<_Ty>(_RANGES size(_Range)); + } + // clang-format on + }; + + inline namespace _Cpos { + inline constexpr _Ssize_fn ssize; + } + + // VARIABLE ranges::next class _Next_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -3279,10 +3308,9 @@ namespace ranges { } }; - // VARIABLE ranges::next inline constexpr _Next_fn next{_Not_quite_object::_Construct_tag{}}; - // CLASS ranges::_Prev_fn + // VARIABLE ranges::prev class _Prev_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -3308,7 +3336,6 @@ namespace ranges { } }; - // VARIABLE ranges::prev inline constexpr _Prev_fn prev{_Not_quite_object::_Construct_tag{}}; // FUNCTION TEMPLATE _Find_last_iterator diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 61292ad030b..36e2e531a99 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -204,6 +204,7 @@ // P1871R1 disable_sized_sentinel_for // P1872R0 span Should Have size_type, Not index_type // P1878R1 Constraining Readable Types +// P1907R2 ranges::ssize // P1956R1 has_single_bit(), bit_ceil(), bit_floor(), bit_width() // P1959R0 Removing weak_equality And strong_equality // P1964R2 Replacing boolean With boolean-testable diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index f74ed9425d7..fae06afc254 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp @@ -61,6 +61,9 @@ concept CanEmpty = requires(R&& r) { ranges::empty(std::forward(r)); }; template concept CanSize = requires(R&& r) { ranges::size(std::forward(r)); }; +template +concept CanSSize = requires(R&& r) { ranges::ssize(std::forward(r)); }; + template concept CanSizeType = requires { typename ranges::range_size_t; }; @@ -116,6 +119,7 @@ STATIC_ASSERT(test_cpo(ranges::rend)); STATIC_ASSERT(test_cpo(ranges::crbegin)); STATIC_ASSERT(test_cpo(ranges::crend)); STATIC_ASSERT(test_cpo(ranges::size)); +STATIC_ASSERT(test_cpo(ranges::ssize)); STATIC_ASSERT(test_cpo(ranges::empty)); STATIC_ASSERT(test_cpo(ranges::data)); STATIC_ASSERT(test_cpo(ranges::cdata)); @@ -136,6 +140,7 @@ void test_cpo_ambiguity() { (void) crbegin(vri); (void) crend(vri); (void) size(vri); + (void) ssize(vri); (void) empty(vri); (void) data(vri); (void) cdata(vri); @@ -315,16 +320,20 @@ constexpr bool test_empty() { template constexpr bool test_size() { - // Validate ranges::size and ranges::sized_range + // Validate ranges::size, ranges::sized_range, and ranges::ssize STATIC_ASSERT(!is_valid || std::integral); STATIC_ASSERT(CanSize == is_valid); + STATIC_ASSERT(CanSSize == is_valid); STATIC_ASSERT(CanSizeType == is_valid); STATIC_ASSERT(ranges::sized_range == is_valid); if constexpr (is_valid) { STATIC_ASSERT(std::same_as())), Size>); STATIC_ASSERT(std::same_as, Size>); + using SignedSize = std::common_type_t>; + STATIC_ASSERT(std::same_as())), SignedSize>); + STATIC_ASSERT(CanEmpty); } @@ -1612,6 +1621,9 @@ namespace exhaustive_size_and_view_test { STATIC_ASSERT(ranges::sized_range == is_valid); if constexpr (is_valid) { STATIC_ASSERT(std::same_as())), Size>); + + using SignedSize = std::common_type_t>; + STATIC_ASSERT(std::same_as())), SignedSize>); } STATIC_ASSERT(ranges::view == IsView);