diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -291,7 +291,7 @@ "`3387 `__","|sect|\ [range.reverse.view] ``reverse_view``\ unintentionally requires ``range``\ ","Prague","","","|ranges|" "`3388 `__","``view``\ iterator types have ill-formed ``<=>``\ operators","Prague","","","|ranges|" "`3389 `__","A move-only iterator still does not have a ``counted_iterator``\ ","Prague","","","|ranges|" -"`3390 `__","``make_move_iterator()``\ cannot be used to construct a ``move_iterator``\ for a move-only iterator","Prague","","","|ranges|" +"`3390 `__","``make_move_iterator()``\ cannot be used to construct a ``move_iterator``\ for a move-only iterator","Prague","|Complete|","14.0","|ranges|" "`3393 `__","Missing/incorrect feature test macro for coroutines","Prague","|Complete|","14.0" "`3395 `__","Definition for three-way comparison needs to be updated (US 152)","Prague","","","|spaceship|" "`3396 `__","Clarify point of reference for ``source_location::current()``\ (DE 169)","Prague","","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -234,6 +234,7 @@ __iterator/iterator.h __iterator/iterator_traits.h __iterator/move_iterator.h + __iterator/move_sentinel.h __iterator/next.h __iterator/ostream_iterator.h __iterator/ostreambuf_iterator.h diff --git a/libcxx/include/__iterator/move_iterator.h b/libcxx/include/__iterator/move_iterator.h --- a/libcxx/include/__iterator/move_iterator.h +++ b/libcxx/include/__iterator/move_iterator.h @@ -10,8 +10,20 @@ #ifndef _LIBCPP___ITERATOR_MOVE_ITERATOR_H #define _LIBCPP___ITERATOR_MOVE_ITERATOR_H +#include <__compare/compare_three_way_result.h> +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/derived_from.h> +#include <__concepts/same_as.h> #include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> +#include <__iterator/move_sentinel.h> +#include <__iterator/readable_traits.h> +#include <__utility/move.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -20,20 +32,43 @@ _LIBCPP_BEGIN_NAMESPACE_STD +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) +template +struct __move_iter_category_base {}; + +template + requires requires { typename iterator_traits<_Iter>::iterator_category; } +struct __move_iter_category_base<_Iter> { + using iterator_category = _If< + derived_from::iterator_category, random_access_iterator_tag>, + random_access_iterator_tag, + typename iterator_traits<_Iter>::iterator_category + >; +}; +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + template class _LIBCPP_TEMPLATE_VIS move_iterator +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + : public __move_iter_category_base<_Iter> +#endif { public: -#if _LIBCPP_STD_VER > 17 - typedef input_iterator_tag iterator_concept; -#endif - +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + using iterator_type = _Iter; + using iterator_concept = input_iterator_tag; + // iterator_category is inherited and not always present + using value_type = iter_value_t<_Iter>; + using difference_type = iter_difference_t<_Iter>; + using pointer = _Iter; + using reference = iter_rvalue_reference_t<_Iter>; +#else typedef _Iter iterator_type; typedef _If< __is_cpp17_random_access_iterator<_Iter>::value, random_access_iterator_tag, typename iterator_traits<_Iter>::iterator_category - > iterator_category; + > iterator_category; typedef typename iterator_traits::value_type value_type; typedef typename iterator_traits::difference_type difference_type; typedef iterator_type pointer; @@ -49,18 +84,41 @@ typedef typename iterator_traits::reference reference; #endif +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 - move_iterator() : __current_() {} + explicit move_iterator(_Iter __i) : __current_(_VSTD::move(__i)) {} +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 - explicit move_iterator(_Iter __i) : __current_(__i) {} + move_iterator() requires is_constructible_v<_Iter> : __current_() {} + + template + requires (!_IsSame<_Up, _Iter>::value) && convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr + move_iterator(const move_iterator<_Up>& __u) : __current_(__u.base()) {} +#else + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 + move_iterator() : __current_() {} template ::value && is_convertible::value > > _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator(const move_iterator<_Up>& __u) : __current_(__u.base()) {} +#endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + template + requires (!_IsSame<_Up, _Iter>::value) && + convertible_to && + assignable_from<_Iter&, const _Up&> + _LIBCPP_HIDE_FROM_ABI constexpr + move_iterator& operator=(const move_iterator<_Up>& __u) { + __current_ = __u.base(); + return *this; + } +#else template ::value && is_convertible::value && @@ -71,21 +129,48 @@ __current_ = __u.base(); return *this; } +#endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + _LIBCPP_HIDE_FROM_ABI constexpr const _Iter& base() const & noexcept { return __current_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() && { return _VSTD::move(__current_); } +#else _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 _Iter base() const { return __current_; } +#endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + _LIBCPP_HIDE_FROM_ABI constexpr + reference operator*() const { return ranges::iter_move(__current_); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 + reference operator[](difference_type __n) const { return ranges::iter_move(__current_ + __n); } +#else _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 reference operator*() const { return static_cast(*__current_); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 - pointer operator->() const { return __current_; } + pointer operator->() const { return __current_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 reference operator[](difference_type __n) const { return static_cast(__current_[__n]); } +#endif _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator& operator++() { ++__current_; return *this; } + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + _LIBCPP_HIDE_FROM_ABI constexpr + auto operator++(int) + requires forward_iterator<_Iter> + { + move_iterator __tmp(*this); ++__current_; return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr + void operator++(int) { ++__current_; } +#else _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator operator++(int) { move_iterator __tmp(*this); ++__current_; return __tmp; } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator& operator--() { --__current_; return *this; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -99,7 +184,48 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator& operator-=(difference_type __n) { __current_ -= __n; return *this; } +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr + bool operator==(const move_iterator& __x, const move_sentinel<_Sent>& __y) + requires requires { { __x.base() == __y.base() } -> convertible_to; } + { + return __x.base() == __y.base(); + } + + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr + iter_difference_t<_Iter> operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y) + { + return __x.base() - __y.base(); + } + + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr + iter_difference_t<_Iter> operator-(const move_iterator& __x, const move_sentinel<_Sent>& __y) + { + return __x.base() - __y.base(); + } + + friend _LIBCPP_HIDE_FROM_ABI constexpr + iter_rvalue_reference_t<_Iter> iter_move(const move_iterator& __i) + noexcept(noexcept(ranges::iter_move(__i.__current_))) + { + return ranges::iter_move(__i.__current_); + } + + template _It2> + friend _LIBCPP_HIDE_FROM_ABI constexpr + void iter_swap(const move_iterator& __x, const move_iterator<_It2>& __y) + noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_))) + { + return ranges::iter_swap(__x.__current_, __y.__current_); + } +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + private: + template friend class move_iterator; + _Iter __current_; }; @@ -110,12 +236,14 @@ return __x.base() == __y.base(); } +#if _LIBCPP_STD_VER <= 17 template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 bool operator!=(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { return __x.base() != __y.base(); } +#endif // _LIBCPP_STD_VER <= 17 template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -145,6 +273,16 @@ return __x.base() >= __y.base(); } +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) +template +inline _LIBCPP_HIDE_FROM_ABI constexpr +auto operator<=>(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) + -> compare_three_way_result_t<_Iter1, _Iter2> +{ + return __x.base() <=> __y.base(); +} +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + #ifndef _LIBCPP_CXX03_LANG template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -163,6 +301,15 @@ } #endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) +template +inline _LIBCPP_HIDE_FROM_ABI constexpr +move_iterator<_Iter> operator+(iter_difference_t<_Iter> __n, const move_iterator<_Iter>& __x) + requires requires { { __x.base() + __n } -> same_as<_Iter>; } +{ + return __x + __n; +} +#else template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator<_Iter> @@ -170,13 +317,14 @@ { return move_iterator<_Iter>(__x.base() + __n); } +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator<_Iter> make_move_iterator(_Iter __i) { - return move_iterator<_Iter>(__i); + return move_iterator<_Iter>(_VSTD::move(__i)); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__iterator/move_sentinel.h b/libcxx/include/__iterator/move_sentinel.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__iterator/move_sentinel.h @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_MOVE_SENTINEL_H +#define _LIBCPP___ITERATOR_MOVE_SENTINEL_H + +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/semiregular.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +template +class _LIBCPP_TEMPLATE_VIS move_sentinel +{ +public: + _LIBCPP_HIDE_FROM_ABI + move_sentinel() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr + explicit move_sentinel(_Sent __s) : __last_(_VSTD::move(__s)) {} + + template + requires convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr + move_sentinel(const move_sentinel<_S2>& __s) : __last_(__s.__last_) {} + + template + requires assignable_from<_Sent, const _S2&> + _LIBCPP_HIDE_FROM_ABI constexpr + move_sentinel& operator=(const move_sentinel<_S2>& __s) + { __last_ = __s.__last_; return *this; } + + constexpr _Sent base() const { return __last_; } + +private: + _Sent __last_; +}; + +#endif // _LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_MOVE_SENTINEL_H diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -607,6 +607,7 @@ #include <__iterator/iterator.h> #include <__iterator/iterator_traits.h> #include <__iterator/move_iterator.h> +#include <__iterator/move_sentinel.h> #include <__iterator/next.h> #include <__iterator/ostream_iterator.h> #include <__iterator/ostreambuf_iterator.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -616,6 +616,7 @@ module iterator { private header "__iterator/iterator.h" } module iterator_traits { private header "__iterator/iterator_traits.h" } module move_iterator { private header "__iterator/move_iterator.h" } + module move_sentinel { private header "__iterator/move_sentinel.h" } module next { private header "__iterator/next.h" export __function_like diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/iterator/move_sentinel.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/iterator/move_sentinel.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/iterator/move_sentinel.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__iterator/move_sentinel.h'}} +#include <__iterator/move_sentinel.h> diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp @@ -16,33 +16,73 @@ #include #include +#include #include "test_macros.h" #include "test_iterators.h" template -void -test(It i) +TEST_CONSTEXPR_CXX17 bool test() { - std::move_iterator r(i); - assert(r.base() == i); + static_assert( std::is_constructible, const It&>::value, ""); + static_assert( std::is_constructible, It&&>::value, ""); + static_assert(!std::is_convertible>::value, ""); + static_assert(!std::is_convertible>::value, ""); + + char s[] = "123"; + { + It it = It(s); + std::move_iterator r(it); + assert(base(r.base()) == s); + } + { + It it = It(s); + std::move_iterator r(std::move(it)); + assert(base(r.base()) == s); + } + return true; +} + +template +TEST_CONSTEXPR_CXX17 bool test_moveonly() +{ + static_assert(!std::is_constructible, const It&>::value, ""); + static_assert( std::is_constructible, It&&>::value, ""); + static_assert(!std::is_convertible>::value, ""); + static_assert(!std::is_convertible>::value, ""); + + char s[] = "123"; + { + It it = It(s); + std::move_iterator r(std::move(it)); + assert(base(r.base()) == s); + } + return true; } int main(int, char**) { - char s[] = "123"; - test(cpp17_input_iterator(s)); - test(forward_iterator(s)); - test(bidirectional_iterator(s)); - test(random_access_iterator(s)); - test(s); + test >(); + test >(); + test >(); + test >(); + test(); + test(); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - constexpr std::move_iterator it(p); - static_assert(it.base() == p); - } + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test()); + static_assert(test()); +#endif + +#if TEST_STD_VER > 17 + test>(); + test_moveonly>(); + static_assert(test>()); + static_assert(test_moveonly>()); #endif return 0; diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp @@ -13,35 +13,41 @@ // pointer operator->() const; // // constexpr in C++17 +// removed in C++20 #include #include #include "test_macros.h" -template -void -test(It i) +#if TEST_STD_VER > 17 +template +concept HasArrow = requires (T t) { + t.operator->(); +}; +static_assert(!HasArrow>); +static_assert(!HasArrow&>); +static_assert(!HasArrow&&>); +#endif // TEST_STD_VER > 17 + +TEST_CONSTEXPR_CXX17 bool test() { - std::move_iterator r(i); - assert(r.operator->() == i); +#if TEST_STD_VER <= 17 + char a[] = "123456789"; + std::move_iterator it1 = std::make_move_iterator(a); + std::move_iterator it2 = std::make_move_iterator(a + 1); + assert(it1.operator->() == a); + assert(it2.operator->() == a + 1); +#endif + return true; } int main(int, char**) { - char s[] = "123"; - test(s); - + test(); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p+1); - static_assert(it1.operator->() == p, ""); - static_assert(it2.operator->() == p + 1, ""); - } + static_assert(test()); #endif - return 0; + return 0; } diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp @@ -56,6 +56,9 @@ m_value = src.m_value; return *this; } + + char& operator*() const; + char *m_value; }; diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp @@ -13,14 +13,100 @@ #include -using iterator = std::move_iterator; - -static_assert(std::input_iterator); -static_assert(!std::forward_iterator); -static_assert(!std::indirectly_writable); -static_assert(std::incrementable); -static_assert(std::sentinel_for); -static_assert(std::sized_sentinel_for); -static_assert(!std::indirectly_movable); -static_assert(!std::indirectly_movable_storable); -static_assert(!std::indirectly_swappable); +#include "test_iterators.h" +#include "test_macros.h" + +void test() +{ + { + using iterator = std::move_iterator>; + + LIBCPP_STATIC_ASSERT(!std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert(!std::sentinel_for); // not copyable + static_assert(!std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + LIBCPP_STATIC_ASSERT(!std::default_initializable); + static_assert(!std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert(!std::sentinel_for); // not copyable + static_assert(!std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert(!std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert(!std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert( std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert( std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert( std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } +}