diff --git a/stl/inc/xutility b/stl/inc/xutility index 5755411c1bf..8b2f7efeb96 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2155,6 +2155,19 @@ public: return _Current == _Se; } + template <_Not_a_const_iterator _Other> + requires _Constant_iterator<_Other> && convertible_to + _NODISCARD constexpr operator _Other() const& noexcept( + is_nothrow_convertible_v) /* strengthened */ { + return _Current; + } + + template <_Not_a_const_iterator _Other> + requires _Constant_iterator<_Other> && convertible_to<_Iter, _Other> + _NODISCARD constexpr operator _Other() && noexcept(is_nothrow_convertible_v<_Iter, _Other>) /* strengthened */ { + return _STD move(_Current); + } + _NODISCARD constexpr bool operator<(const basic_const_iterator& _Right) const noexcept(noexcept(_Fake_copy_init(_Current < _Right._Current))) // strengthened requires random_access_iterator<_Iter> diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 1c494ad1100..350b1e22fa4 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -383,6 +383,7 @@ // P2693R1 Formatting thread::id And stacktrace // P2713R1 Escaping Improvements In std::format // P2763R1 Fixing layout_stride's Default Constructor For Fully Static Extents +// P2836R1 basic_const_iterator Should Follow Its Underlying Type's Convertibility // _HAS_CXX23 and _SILENCE_ALL_CXX23_DEPRECATION_WARNINGS control: // P1413R3 Deprecate aligned_storage And aligned_union @@ -1831,7 +1832,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #ifdef __cpp_lib_concepts #define __cpp_lib_out_ptr 202106L #define __cpp_lib_print 202207L -#define __cpp_lib_ranges_as_const 202207L +#define __cpp_lib_ranges_as_const 202311L #define __cpp_lib_ranges_as_rvalue 202207L #define __cpp_lib_ranges_cartesian_product 202207L #define __cpp_lib_ranges_chunk 202202L diff --git a/tests/std/tests/P2278R4_basic_const_iterator/test.cpp b/tests/std/tests/P2278R4_basic_const_iterator/test.cpp index a21fbf86350..6db5eca75b8 100644 --- a/tests/std/tests/P2278R4_basic_const_iterator/test.cpp +++ b/tests/std/tests/P2278R4_basic_const_iterator/test.cpp @@ -298,7 +298,89 @@ constexpr void instantiation_test() { instantiator::call>(); } -int main() { - static_assert((instantiation_test(), true)); +template +class tracking_input_iterator { +public: + using value_type = remove_const_t; + using difference_type = ptrdiff_t; + + constexpr tracking_input_iterator() = default; + + constexpr tracking_input_iterator(const tracking_input_iterator&) : copied{true} {} + + constexpr tracking_input_iterator(tracking_input_iterator&&) : moved{true} {} + + template + requires convertible_to + constexpr tracking_input_iterator(const tracking_input_iterator&) : copied{true} {} + + template + requires convertible_to + constexpr tracking_input_iterator(tracking_input_iterator&&) : moved{true} {} + + tracking_input_iterator& operator=(const tracking_input_iterator&) = default; + tracking_input_iterator& operator=(tracking_input_iterator&&) = default; + + constexpr tracking_input_iterator& operator++(); // not defined + constexpr void operator++(int); // not defined + T& operator*() const; // not defined + + constexpr bool is_copied() const { + return copied; + } + + constexpr bool is_moved() const { + return moved; + } + +private: + bool copied = false; + bool moved = false; +}; + +static_assert(input_iterator>); +static_assert(!_Constant_iterator>); +static_assert(_Constant_iterator>); + +// P2836R1 basic_const_iterator Should Follow Its Underlying Type's Convertibility +constexpr void test_p2836r1() { + { // Code from P2836R1 + vector v; + auto t = v | views::take_while([](const int x) { return x < 100; }); + auto f = [](vector::const_iterator) {}; + auto i2 = ranges::cbegin(t); + f(i2); // Error before P2836R1 + } + + { + tracking_input_iterator i; + basic_const_iterator ci{i}; + + tracking_input_iterator j1 = ci; + assert(j1.is_copied()); + assert(!j1.is_moved()); + + tracking_input_iterator j2 = move(ci); + assert(!j2.is_copied()); + assert(j2.is_moved()); + + // Incorrect conversions + static_assert(!constructible_from, const decltype(ci)&>); + static_assert(!constructible_from, decltype(ci)>); + + // Non-const target iterator + static_assert(!constructible_from, const decltype(ci)&>); + static_assert(!constructible_from, decltype(ci)>); + } +} + +constexpr bool all_tests() { instantiation_test(); + test_p2836r1(); + return true; +} + +int main() { + static_assert(all_tests()); + all_tests(); } diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 3ab7a981fe3..0d371607055 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -674,7 +674,7 @@ STATIC_ASSERT(__cpp_lib_ranges == 202110L); #endif #if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 -STATIC_ASSERT(__cpp_lib_ranges_as_const == 202207L); +STATIC_ASSERT(__cpp_lib_ranges_as_const == 202311L); #elif defined(__cpp_lib_ranges_as_const) #error __cpp_lib_ranges_as_const is defined #endif