P2278R4: `cbegin` should always return a constant iterator ("Ranges" and "Span" sections) (#3187)

Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
Jakub Mazurkiewicz 2022-11-11 23:57:19 +01:00 коммит произвёл GitHub
Родитель 0743f64584
Коммит 0b13eb07d2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 856 добавлений и 88 удалений

Просмотреть файл

@ -33,6 +33,17 @@ namespace ranges {
template <class _Ty>
inline constexpr bool _Is_initializer_list = _Is_specialization_v<remove_cvref_t<_Ty>, initializer_list>;
#if _HAS_CXX23
_EXPORT_STD template <range _Rng>
using const_iterator_t = const_iterator<iterator_t<_Rng>>;
_EXPORT_STD template <range _Rng>
using const_sentinel_t = const_sentinel<sentinel_t<_Rng>>;
_EXPORT_STD template <range _Rng>
using range_const_reference_t = iter_const_reference_t<iterator_t<_Rng>>;
#endif // _HAS_CXX23
// clang-format off
_EXPORT_STD template <class _Rng>
concept viewable_range = range<_Rng>
@ -45,20 +56,19 @@ namespace ranges {
concept _Simple_view = view<_Rng> && range<const _Rng>
&& same_as<iterator_t<_Rng>, iterator_t<const _Rng>>
&& same_as<sentinel_t<_Rng>, sentinel_t<const _Rng>>;
// clang-format on
template <class _Ty>
concept _Valid_movable_box_object =
#if _HAS_CXX23
move_constructible<_Ty>
move_constructible<_Ty>
#else // ^^^ C++23 / C++20 vvv
copy_constructible<_Ty>
copy_constructible<_Ty>
#endif // C++20
&& _Destructible_object<_Ty>;
&& _Destructible_object<_Ty>;
template <class _It>
concept _Has_arrow = input_iterator<_It>
&& (is_pointer_v<_It> || _Has_member_arrow<_It&>);
// clang-format on
concept _Has_arrow = input_iterator<_It> && (is_pointer_v<_It> || _Has_member_arrow<_It&>);
template <bool _IsConst, class _Ty>
using _Maybe_const = conditional_t<_IsConst, const _Ty, _Ty>;

Просмотреть файл

@ -17,7 +17,6 @@ _EMIT_STL_WARNING(STL4038, "The contents of <span> are available only with C++20
#include <type_traits>
#include <xutility>
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
@ -312,16 +311,20 @@ private:
using _Mybase::_Mysize;
public:
using element_type = _Ty;
using value_type = remove_cv_t<_Ty>;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = _Ty*;
using const_pointer = const _Ty*;
using reference = _Ty&;
using const_reference = const _Ty&;
using iterator = _Span_iterator<_Ty>;
using reverse_iterator = _STD reverse_iterator<iterator>;
using element_type = _Ty;
using value_type = remove_cv_t<_Ty>;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = _Ty*;
using const_pointer = const _Ty*;
using reference = _Ty&;
using const_reference = const _Ty&;
using iterator = _Span_iterator<_Ty>;
using reverse_iterator = _STD reverse_iterator<iterator>;
#if _HAS_CXX23 && defined(__cpp_lib_concepts)
using const_iterator = _STD const_iterator<iterator>;
using const_reverse_iterator = _STD const_iterator<reverse_iterator>;
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
static constexpr size_type extent = _Extent;
@ -617,6 +620,16 @@ public:
#endif // _ITERATOR_DEBUG_LEVEL
}
#if _HAS_CXX23 && defined(__cpp_lib_concepts)
_NODISCARD constexpr const_iterator cbegin() const noexcept {
return begin();
}
_NODISCARD constexpr const_iterator cend() const noexcept {
return end();
}
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
_NODISCARD constexpr reverse_iterator rbegin() const noexcept {
return reverse_iterator{end()};
}
@ -625,6 +638,16 @@ public:
return reverse_iterator{begin()};
}
#if _HAS_CXX23 && defined(__cpp_lib_concepts)
_NODISCARD constexpr const_reverse_iterator crbegin() const noexcept {
return rbegin();
}
_NODISCARD constexpr const_reverse_iterator crend() const noexcept {
return rend();
}
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
_NODISCARD constexpr pointer _Unchecked_begin() const noexcept {
return _Mydata;
}

Просмотреть файл

@ -2233,6 +2233,9 @@ namespace ranges {
_RANGES end(__r);
};
_EXPORT_STD template <class _Rng>
concept input_range = range<_Rng> && input_iterator<iterator_t<_Rng>>;
_EXPORT_STD template <range _Rng>
using sentinel_t = decltype(_RANGES end(_STD declval<_Rng&>()));
@ -2426,15 +2429,44 @@ namespace ranges {
_EXPORT_STD template <range _Rng>
using range_rvalue_reference_t = iter_rvalue_reference_t<iterator_t<_Rng>>;
#if _HAS_CXX23
_EXPORT_STD template <class _Rng>
concept constant_range = input_range<_Rng> && _Constant_iterator<iterator_t<_Rng>>;
template <input_range _Rng>
_NODISCARD constexpr auto& _Possibly_const_range(_Rng& _Range) noexcept {
if constexpr (constant_range<const _Rng> && !constant_range<_Rng>) {
return _STD as_const(_Range);
} else {
return _Range;
}
}
template <class _Ty>
_NODISCARD constexpr auto _As_const_pointer(const _Ty* _Ptr) noexcept {
return _Ptr;
}
#endif // _HAS_CXX23
struct _Cbegin_fn {
// clang-format off
#if _HAS_CXX23
template <_Should_range_access _Ty,
class _Uty = decltype(_RANGES begin(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(const_iterator<_Uty>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}))
requires requires { const_iterator<_Uty>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}; }
{
return const_iterator<_Uty>{_RANGES begin(_RANGES _Possibly_const_range(_Val))};
}
#else // ^^^ C++23 / C++20 vvv
template <class _Ty, class _CTy = _Const_thru_ref<_Ty>>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(_RANGES begin(static_cast<_CTy&&>(_Val))))
requires requires { _RANGES begin(static_cast<_CTy&&>(_Val)); } {
requires requires { _RANGES begin(static_cast<_CTy&&>(_Val)); }
{
return _RANGES begin(static_cast<_CTy&&>(_Val));
}
// clang-format on
#endif // C++20
};
inline namespace _Cpos {
@ -2442,14 +2474,24 @@ namespace ranges {
}
struct _Cend_fn {
// clang-format off
#if _HAS_CXX23
template <_Should_range_access _Ty,
class _Uty = decltype(_RANGES end(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(const_sentinel<_Uty>{_RANGES end(_RANGES _Possibly_const_range(_Val))}))
requires requires { const_sentinel<_Uty>{_RANGES end(_RANGES _Possibly_const_range(_Val))}; }
{
return const_sentinel<_Uty>{_RANGES end(_RANGES _Possibly_const_range(_Val))};
}
#else // ^^^ C++23 / C++20 vvv
template <class _Ty, class _CTy = _Const_thru_ref<_Ty>>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(_RANGES end(static_cast<_CTy&&>(_Val))))
requires requires { _RANGES end(static_cast<_CTy&&>(_Val)); } {
requires requires { _RANGES end(static_cast<_CTy&&>(_Val)); }
{
return _RANGES end(static_cast<_CTy&&>(_Val));
}
// clang-format on
#endif // C++20
};
inline namespace _Cpos {
@ -2592,14 +2634,24 @@ namespace ranges {
}
struct _Crbegin_fn {
// clang-format off
#if _HAS_CXX23
template <_Should_range_access _Ty,
class _Uty = decltype(_RANGES rbegin(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(const_iterator<_Uty>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}))
requires requires { const_iterator<_Uty>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}; }
{
return const_iterator<_Uty>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))};
}
#else // ^^^ C++23 / C++20 vvv
template <class _Ty, class _CTy = _Const_thru_ref<_Ty>>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(_RANGES rbegin(static_cast<_CTy&&>(_Val))))
requires requires { _RANGES rbegin(static_cast<_CTy&&>(_Val)); } {
requires requires { _RANGES rbegin(static_cast<_CTy&&>(_Val)); }
{
return _RANGES rbegin(static_cast<_CTy&&>(_Val));
}
// clang-format on
#endif // C++20
};
inline namespace _Cpos {
@ -2607,14 +2659,24 @@ namespace ranges {
}
struct _Crend_fn {
// clang-format off
#if _HAS_CXX23
template <_Should_range_access _Ty,
class _Uty = decltype(_RANGES rend(_RANGES _Possibly_const_range(_STD declval<_Ty&>())))>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(const_sentinel<_Uty>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}))
requires requires { const_sentinel<_Uty>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}; }
{
return const_sentinel<_Uty>{_RANGES rend(_RANGES _Possibly_const_range(_Val))};
}
#else // ^^^ C++23 / C++20 vvv
template <class _Ty, class _CTy = _Const_thru_ref<_Ty>>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(_RANGES rend(static_cast<_CTy&&>(_Val))))
requires requires { _RANGES rend(static_cast<_CTy&&>(_Val)); } {
requires requires { _RANGES rend(static_cast<_CTy&&>(_Val)); }
{
return _RANGES rend(static_cast<_CTy&&>(_Val));
}
// clang-format on
#endif // C++20
};
inline namespace _Cpos {
@ -2823,14 +2885,23 @@ namespace ranges {
}
struct _Cdata_fn {
// clang-format off
#if _HAS_CXX23
template <_Should_range_access _Ty>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(_RANGES data(_RANGES _Possibly_const_range(_Val))))
requires requires { _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val))); }
{
return _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val)));
}
#else // ^^^ C++23 / C++20 vvv
template <class _Ty, class _CTy = _Const_thru_ref<_Ty>>
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
noexcept(noexcept(_RANGES data(static_cast<_CTy&&>(_Val))))
requires requires { _RANGES data(static_cast<_CTy&&>(_Val)); } {
requires requires { _RANGES data(static_cast<_CTy&&>(_Val)); }
{
return _RANGES data(static_cast<_CTy&&>(_Val));
}
// clang-format on
#endif // C++20
};
inline namespace _Cpos {
@ -2869,9 +2940,6 @@ namespace ranges {
_EXPORT_STD template <class _Rng, class _Ty>
concept output_range = range<_Rng> && output_iterator<iterator_t<_Rng>, _Ty>;
_EXPORT_STD template <class _Rng>
concept input_range = range<_Rng> && input_iterator<iterator_t<_Rng>>;
_EXPORT_STD template <class _Rng>
concept forward_range = range<_Rng> && forward_iterator<iterator_t<_Rng>>;
@ -3192,7 +3260,6 @@ namespace ranges {
template <class _Ty>
concept _Can_empty = requires(_Ty __t) { _RANGES empty(__t); };
// clang-format off
_EXPORT_STD template <class _Derived>
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
class view_interface {
@ -3216,9 +3283,11 @@ namespace ranges {
public:
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr bool empty() requires sized_range<_Dx> || forward_range<_Dx>
_NODISCARD constexpr bool empty()
requires sized_range<_Dx> || forward_range<_Dx>
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr bool empty() requires sized_range<_Derived> || forward_range<_Derived>
_NODISCARD constexpr bool empty()
requires sized_range<_Derived> || forward_range<_Derived>
#endif // TRANSITION, LLVM-44833
{
auto& _Self = _Cast();
@ -3231,9 +3300,11 @@ namespace ranges {
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr bool empty() const requires sized_range<const _Dx> || forward_range<const _Dx>
_NODISCARD constexpr bool empty() const
requires sized_range<const _Dx> || forward_range<const _Dx>
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr bool empty() const requires sized_range<const _Derived> || forward_range<const _Derived>
_NODISCARD constexpr bool empty() const
requires sized_range<const _Derived> || forward_range<const _Derived>
#endif // TRANSITION, LLVM-44833
{
auto& _Self = _Cast();
@ -3244,11 +3315,63 @@ namespace ranges {
}
}
#if _HAS_CXX23
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
constexpr explicit operator bool() requires _Can_empty<_Dx>
_NODISCARD constexpr auto cbegin()
requires input_range<_Dx> // Per LWG-3766
#else // ^^^ workaround / no workaround vvv
constexpr explicit operator bool() requires _Can_empty<_Derived>
_NODISCARD constexpr auto cbegin()
requires input_range<_Derived> // Per LWG-3766
#endif // TRANSITION, LLVM-44833
{
return _RANGES cbegin(_Cast());
}
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr auto cbegin() const
requires input_range<const _Dx> // Per LWG-3766
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr auto cbegin() const
requires input_range<const _Derived> // Per LWG-3766
#endif // TRANSITION, LLVM-44833
{
return _RANGES cbegin(_Cast());
}
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr auto cend()
requires input_range<_Dx> // Per LWG-3766
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr auto cend()
requires input_range<_Derived> // Per LWG-3766
#endif // TRANSITION, LLVM-44833
{
return _RANGES cend(_Cast());
}
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr auto cend() const
requires input_range<const _Dx> // Per LWG-3766
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr auto cend() const
requires input_range<const _Derived> // Per LWG-3766
#endif // TRANSITION, LLVM-44833
{
return _RANGES cend(_Cast());
}
#endif // _HAS_CXX23
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
constexpr explicit operator bool()
requires _Can_empty<_Dx>
#else // ^^^ workaround / no workaround vvv
constexpr explicit operator bool()
requires _Can_empty<_Derived>
#endif // TRANSITION, LLVM-44833
{
return !_RANGES empty(_Cast());
@ -3256,9 +3379,11 @@ namespace ranges {
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
constexpr explicit operator bool() const requires _Can_empty<const _Dx>
constexpr explicit operator bool() const
requires _Can_empty<const _Dx>
#else // ^^^ workaround / no workaround vvv
constexpr explicit operator bool() const requires _Can_empty<const _Derived>
constexpr explicit operator bool() const
requires _Can_empty<const _Derived>
#endif // TRANSITION, LLVM-44833
{
return !_RANGES empty(_Cast());
@ -3266,9 +3391,11 @@ namespace ranges {
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr auto data() requires contiguous_iterator<iterator_t<_Dx>>
_NODISCARD constexpr auto data()
requires contiguous_iterator<iterator_t<_Dx>>
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr auto data() requires contiguous_iterator<iterator_t<_Derived>>
_NODISCARD constexpr auto data()
requires contiguous_iterator<iterator_t<_Derived>>
#endif // TRANSITION, LLVM-44833
{
return _STD to_address(_RANGES begin(_Cast()));
@ -3301,11 +3428,12 @@ namespace ranges {
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr auto size() const requires forward_range<const _Dx>
&& sized_sentinel_for<sentinel_t<const _Dx>, iterator_t<const _Dx>>
_NODISCARD constexpr auto size() const
requires forward_range<const _Dx> && sized_sentinel_for<sentinel_t<const _Dx>, iterator_t<const _Dx>>
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr auto size() const requires forward_range<const _Derived>
&& sized_sentinel_for<sentinel_t<const _Derived>, iterator_t<const _Derived>>
_NODISCARD constexpr auto size() const
requires forward_range<const _Derived>
&& sized_sentinel_for<sentinel_t<const _Derived>, iterator_t<const _Derived>>
#endif // TRANSITION, LLVM-44833
{
auto& _Self = _Cast();
@ -3314,9 +3442,11 @@ namespace ranges {
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr decltype(auto) front() requires forward_range<_Dx>
_NODISCARD constexpr decltype(auto) front()
requires forward_range<_Dx>
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr decltype(auto) front() requires forward_range<_Derived>
_NODISCARD constexpr decltype(auto) front()
requires forward_range<_Derived>
#endif // TRANSITION, LLVM-44833
{
auto& _Self = _Cast();
@ -3328,9 +3458,11 @@ namespace ranges {
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr decltype(auto) front() const requires forward_range<const _Dx>
_NODISCARD constexpr decltype(auto) front() const
requires forward_range<const _Dx>
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr decltype(auto) front() const requires forward_range<const _Derived>
_NODISCARD constexpr decltype(auto) front() const
requires forward_range<const _Derived>
#endif // TRANSITION, LLVM-44833
{
auto& _Self = _Cast();
@ -3342,9 +3474,11 @@ namespace ranges {
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr decltype(auto) back() requires bidirectional_range<_Dx> && common_range<_Dx>
_NODISCARD constexpr decltype(auto) back()
requires bidirectional_range<_Dx> && common_range<_Dx>
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr decltype(auto) back() requires bidirectional_range<_Derived> && common_range<_Derived>
_NODISCARD constexpr decltype(auto) back()
requires bidirectional_range<_Derived> && common_range<_Derived>
#endif // TRANSITION, LLVM-44833
{
auto& _Self = _Cast();
@ -3398,7 +3532,6 @@ namespace ranges {
return _RANGES begin(_Self)[_Idx];
}
};
// clang-format on
} // namespace ranges
// These declarations must be visible to qualified name lookup for _STD get in _Pair_like below, even if <tuple> hasn't

Просмотреть файл

@ -325,7 +325,7 @@
// P2186R2 Removing Garbage Collection Support
// P2273R3 constexpr unique_ptr
// P2278R4 cbegin Should Always Return A Constant Iterator
// ("Iterators" section from the paper only)
// (missing views::as_const)
// P2291R3 constexpr Integral <charconv>
// P2302R4 ranges::contains, ranges::contains_subrange
// P2321R2 zip

Просмотреть файл

@ -58,6 +58,14 @@ std/strings/basic.string/string.nonmembers/string_op+/allocator_propagation.pass
# libc++ hasn't updated move_iterator for P2520R0
std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp FAIL
# libc++ has not implemented P2278R4: "cbegin should always return a constant iterator"
std/containers/views/views.span/types.pass.cpp FAIL
std/ranges/range.access/begin.pass.cpp FAIL
std/ranges/range.access/data.pass.cpp FAIL
std/ranges/range.access/end.pass.cpp FAIL
std/ranges/range.access/rbegin.pass.cpp FAIL
std/ranges/range.access/rend.pass.cpp FAIL
# libc++ doesn't implement LWG-3692: "zip_view::iterator's operator<=> is overconstrained"
std/ranges/range.adaptors/range.zip/iterator/compare.pass.cpp FAIL

Просмотреть файл

@ -58,6 +58,14 @@ strings\basic.string\string.nonmembers\string_op+\allocator_propagation.pass.cpp
# libc++ hasn't updated move_iterator for P2520R0
iterators\predef.iterators\move.iterators\move.iterator\types.pass.cpp
# libc++ has not implemented P2278R4: "cbegin should always return a constant iterator"
containers\views\views.span\types.pass.cpp
ranges\range.access\begin.pass.cpp
ranges\range.access\data.pass.cpp
ranges\range.access\end.pass.cpp
ranges\range.access\rbegin.pass.cpp
ranges\range.access\rend.pass.cpp
# libc++ doesn't implement LWG-3692: "zip_view::iterator's operator<=> is overconstrained"
ranges\range.adaptors\range.zip\iterator\compare.pass.cpp

Просмотреть файл

@ -1483,8 +1483,13 @@ concept CanMemberEnd = requires(R&& r) { std::forward<R>(r).end(); };
template <class R>
concept CanCBegin = requires(R&& r) { ranges::cbegin(std::forward<R>(r)); };
template <class R>
concept CanMemberCBegin = requires(R&& r) { std::forward<R>(r).cbegin(); };
template <class R>
concept CanCEnd = requires(R&& r) { ranges::cend(std::forward<R>(r)); };
template <class R>
concept CanMemberCEnd = requires(R&& r) { std::forward<R>(r).cend(); };
template <class R>
concept CanRBegin = requires(R&& r) { ranges::rbegin(std::forward<R>(r)); };

Просмотреть файл

@ -548,7 +548,9 @@ tests\P2162R2_std_visit_for_derived_classes_from_variant
tests\P2231R1_complete_constexpr_optional_variant
tests\P2273R3_constexpr_unique_ptr
tests\P2278R4_basic_const_iterator
tests\P2278R4_const_span
tests\P2278R4_ranges_const_iterator_machinery
tests\P2278R4_ranges_const_range_machinery
tests\P2302R4_ranges_alg_contains
tests\P2302R4_ranges_alg_contains_subrange
tests\P2321R2_proxy_reference

Просмотреть файл

@ -573,7 +573,6 @@ STATIC_ASSERT(!ranges::view<int const[]>);
STATIC_ASSERT(test_begin<int (&)[], int*>());
STATIC_ASSERT(test_end<int (&)[]>());
STATIC_ASSERT(test_cbegin<int (&)[], int const*>());
STATIC_ASSERT(test_cend<int (&)[]>());
STATIC_ASSERT(test_rbegin<int (&)[]>());
STATIC_ASSERT(test_rend<int (&)[]>());
@ -581,15 +580,22 @@ STATIC_ASSERT(test_crbegin<int (&)[]>());
STATIC_ASSERT(test_crend<int (&)[]>());
STATIC_ASSERT(test_size<int (&)[]>());
STATIC_ASSERT(test_empty<int (&)[], false>());
// Can't use test_data/_cdata here because they use range_value_t and this isn't a range
// Can't use test_data here because it uses range_value_t and this isn't a range
STATIC_ASSERT(std::same_as<decltype(ranges::data(std::declval<int (&)[]>())), int*>);
STATIC_ASSERT(std::same_as<decltype(ranges::cdata(std::declval<int (&)[]>())), int const*>);
STATIC_ASSERT(!ranges::range<int (&)[]>);
STATIC_ASSERT(!ranges::view<int (&)[]>);
#if _HAS_CXX23 // ranges::cbegin and ranges::cdata behavior differs in C++20 and C++23 modes
STATIC_ASSERT(test_cbegin<int (&)[]>());
STATIC_ASSERT(test_cdata<int (&)[]>());
#else // ^^^ C++23 / C++20 vvv
STATIC_ASSERT(test_cbegin<int (&)[], int const*>());
// Can't use test_cdata here because it uses range_value_t and this isn't a range
STATIC_ASSERT(std::same_as<decltype(ranges::cdata(std::declval<int (&)[]>())), int const*>);
#endif // C++20
STATIC_ASSERT(test_begin<int const (&)[], int const*>());
STATIC_ASSERT(test_end<int const (&)[]>());
STATIC_ASSERT(test_cbegin<int const (&)[], int const*>());
STATIC_ASSERT(test_cend<int const (&)[]>());
STATIC_ASSERT(test_rbegin<int const (&)[]>());
STATIC_ASSERT(test_rend<int const (&)[]>());
@ -597,17 +603,24 @@ STATIC_ASSERT(test_crbegin<int const (&)[]>());
STATIC_ASSERT(test_crend<int const (&)[]>());
STATIC_ASSERT(test_size<int const (&)[]>());
STATIC_ASSERT(test_empty<int const (&)[], false>());
// Can't use test_data/_cdata here because they use range_value_t and this isn't a range
// Can't use test_data here because it uses range_value_t and this isn't a range
STATIC_ASSERT(std::same_as<decltype(ranges::data(std::declval<int const (&)[]>())), int const*>);
STATIC_ASSERT(std::same_as<decltype(ranges::cdata(std::declval<int const (&)[]>())), int const*>);
STATIC_ASSERT(!ranges::range<int const (&)[]>);
STATIC_ASSERT(!ranges::view<int const (&)[]>);
#if _HAS_CXX23 // ranges::cbegin and ranges::cdata behavior differs in C++20 and C++23 modes
STATIC_ASSERT(test_cbegin<int const (&)[]>());
STATIC_ASSERT(test_cdata<int const (&)[]>());
#else // ^^^ C++23 / C++20 vvv
STATIC_ASSERT(test_cbegin<int const (&)[], int const*>());
// Can't use test_cdata here because it uses range_value_t and this isn't a range
STATIC_ASSERT(std::same_as<decltype(ranges::cdata(std::declval<int const (&)[]>())), int const*>);
#endif // C++20
// Validate behavior before/after completing the bound of an array
extern int initially_unbounded[];
STATIC_ASSERT(ranges::begin(initially_unbounded) == initially_unbounded);
STATIC_ASSERT(!CanEnd<decltype((initially_unbounded))>);
STATIC_ASSERT(ranges::cbegin(initially_unbounded) == initially_unbounded);
STATIC_ASSERT(!CanCEnd<decltype((initially_unbounded))>);
STATIC_ASSERT(!CanRBegin<decltype((initially_unbounded))>);
STATIC_ASSERT(!CanREnd<decltype((initially_unbounded))>);
@ -616,7 +629,15 @@ STATIC_ASSERT(!CanCREnd<decltype((initially_unbounded))>);
STATIC_ASSERT(!CanSize<decltype((initially_unbounded))>);
STATIC_ASSERT(!CanEmpty<decltype((initially_unbounded))>);
STATIC_ASSERT(ranges::data(initially_unbounded) == initially_unbounded);
#if _HAS_CXX23 // ranges::cbegin and ranges::cdata behavior differs in C++20 and C++23 modes
STATIC_ASSERT(!CanCBegin<decltype((initially_unbounded))>);
STATIC_ASSERT(!CanCData<decltype((initially_unbounded))>);
#else // ^^^ C++23 / C++20 vvv
STATIC_ASSERT(ranges::cbegin(initially_unbounded) == initially_unbounded);
STATIC_ASSERT(ranges::cdata(initially_unbounded) == initially_unbounded);
#endif // C++20
int initially_unbounded[42];
STATIC_ASSERT(ranges::begin(initially_unbounded) == initially_unbounded);
STATIC_ASSERT(ranges::end(initially_unbounded) == initially_unbounded + ranges::size(initially_unbounded));
@ -972,64 +993,100 @@ STATIC_ASSERT(!ranges::view<std::string_view const&>);
STATIC_ASSERT(test_begin<std::span<int>, std::span<int>::iterator>());
STATIC_ASSERT(test_end<std::span<int>, std::span<int>::iterator>());
STATIC_ASSERT(test_cbegin<std::span<int>, std::span<int>::iterator>());
STATIC_ASSERT(test_cend<std::span<int>, std::span<int>::iterator>());
STATIC_ASSERT(test_rbegin<std::span<int>, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_rend<std::span<int>, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crbegin<std::span<int>, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crend<std::span<int>, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_size<std::span<int>, std::size_t>());
STATIC_ASSERT(test_empty<std::span<int>, true>());
STATIC_ASSERT(test_data<std::span<int>, int*>());
STATIC_ASSERT(test_cdata<std::span<int>, int*>());
STATIC_ASSERT(test_contiguous_range<std::span<int>>());
STATIC_ASSERT(ranges::view<std::span<int>>);
#if _HAS_CXX23 // behavior of span members differs in C++20 and C++23 modes
STATIC_ASSERT(test_cbegin<std::span<int>, std::span<int>::const_iterator>());
STATIC_ASSERT(test_cend<std::span<int>, std::span<int>::const_iterator>());
STATIC_ASSERT(test_crbegin<std::span<int>, std::span<int>::const_reverse_iterator>());
STATIC_ASSERT(test_crend<std::span<int>, std::span<int>::const_reverse_iterator>());
STATIC_ASSERT(test_cdata<std::span<int>, const int*>());
#else // ^^^ C++23 / C++20 vvv
STATIC_ASSERT(test_cbegin<std::span<int>, std::span<int>::iterator>());
STATIC_ASSERT(test_cend<std::span<int>, std::span<int>::iterator>());
STATIC_ASSERT(test_crbegin<std::span<int>, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crend<std::span<int>, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_cdata<std::span<int>, int*>());
#endif // C++20
STATIC_ASSERT(test_begin<std::span<int> const, std::span<int>::iterator>());
STATIC_ASSERT(test_end<std::span<int> const, std::span<int>::iterator>());
STATIC_ASSERT(test_cbegin<std::span<int> const, std::span<int>::iterator>());
STATIC_ASSERT(test_cend<std::span<int> const, std::span<int>::iterator>());
STATIC_ASSERT(test_rbegin<std::span<int> const, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_rend<std::span<int> const, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crbegin<std::span<int> const, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crend<std::span<int> const, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_size<std::span<int> const, std::size_t>());
STATIC_ASSERT(test_empty<std::span<int> const, true>());
STATIC_ASSERT(test_data<std::span<int> const, int*>());
STATIC_ASSERT(test_cdata<std::span<int> const, int*>());
STATIC_ASSERT(test_contiguous_range<std::span<int> const>());
STATIC_ASSERT(!ranges::view<std::span<int> const>);
#if _HAS_CXX23 // behavior of const span members differs in C++20 and C++23 modes
STATIC_ASSERT(test_cbegin<std::span<int> const, std::span<int>::const_iterator>());
STATIC_ASSERT(test_cend<std::span<int> const, std::span<int>::const_iterator>());
STATIC_ASSERT(test_crbegin<std::span<int> const, std::span<int>::const_reverse_iterator>());
STATIC_ASSERT(test_crend<std::span<int> const, std::span<int>::const_reverse_iterator>());
STATIC_ASSERT(test_cdata<std::span<int> const, const int*>());
#else // ^^^ C++23 / C++20 vvv
STATIC_ASSERT(test_cbegin<std::span<int> const, std::span<int>::iterator>());
STATIC_ASSERT(test_cend<std::span<int> const, std::span<int>::iterator>());
STATIC_ASSERT(test_crbegin<std::span<int> const, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crend<std::span<int> const, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_cdata<std::span<int> const, int*>());
#endif // C++20
STATIC_ASSERT(test_begin<std::span<int>&, std::span<int>::iterator>());
STATIC_ASSERT(test_end<std::span<int>&, std::span<int>::iterator>());
STATIC_ASSERT(test_cbegin<std::span<int>&, std::span<int>::iterator>());
STATIC_ASSERT(test_cend<std::span<int>&, std::span<int>::iterator>());
STATIC_ASSERT(test_rbegin<std::span<int>&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_rend<std::span<int>&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crbegin<std::span<int>&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crend<std::span<int>&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_size<std::span<int>&, std::size_t>());
STATIC_ASSERT(test_empty<std::span<int>&, true>());
STATIC_ASSERT(test_data<std::span<int>&, int*>());
STATIC_ASSERT(test_cdata<std::span<int>&, int*>());
STATIC_ASSERT(test_contiguous_range<std::span<int>&>());
STATIC_ASSERT(!ranges::view<std::span<int>&>);
#if _HAS_CXX23 // behavior of span& members differs in C++20 and C++23 modes
STATIC_ASSERT(test_cbegin<std::span<int>&, std::span<int>::const_iterator>());
STATIC_ASSERT(test_cend<std::span<int>&, std::span<int>::const_iterator>());
STATIC_ASSERT(test_crbegin<std::span<int>&, std::span<int>::const_reverse_iterator>());
STATIC_ASSERT(test_crend<std::span<int>&, std::span<int>::const_reverse_iterator>());
STATIC_ASSERT(test_cdata<std::span<int>&, const int*>());
#else // ^^^ C++23 / C++20 vvv
STATIC_ASSERT(test_cbegin<std::span<int>&, std::span<int>::iterator>());
STATIC_ASSERT(test_cend<std::span<int>&, std::span<int>::iterator>());
STATIC_ASSERT(test_crbegin<std::span<int>&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crend<std::span<int>&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_cdata<std::span<int>&, int*>());
#endif // C++20
STATIC_ASSERT(test_begin<std::span<int> const&, std::span<int>::iterator>());
STATIC_ASSERT(test_end<std::span<int> const&, std::span<int>::iterator>());
STATIC_ASSERT(test_cbegin<std::span<int> const&, std::span<int>::iterator>());
STATIC_ASSERT(test_cend<std::span<int> const&, std::span<int>::iterator>());
STATIC_ASSERT(test_rbegin<std::span<int> const&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_rend<std::span<int> const&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crbegin<std::span<int> const&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crend<std::span<int> const&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_size<std::span<int> const&, std::size_t>());
STATIC_ASSERT(test_empty<std::span<int> const&, true>());
STATIC_ASSERT(test_data<std::span<int> const&, int*>());
STATIC_ASSERT(test_cdata<std::span<int> const&, int*>());
STATIC_ASSERT(test_contiguous_range<std::span<int> const&>());
STATIC_ASSERT(!ranges::view<std::span<int> const&>);
#if _HAS_CXX23 // behavior of const span& members differs in C++20 and C++23 modes
STATIC_ASSERT(test_cbegin<std::span<int> const&, std::span<int>::const_iterator>());
STATIC_ASSERT(test_cend<std::span<int> const&, std::span<int>::const_iterator>());
STATIC_ASSERT(test_crbegin<std::span<int> const&, std::span<int>::const_reverse_iterator>());
STATIC_ASSERT(test_crend<std::span<int> const&, std::span<int>::const_reverse_iterator>());
STATIC_ASSERT(test_cdata<std::span<int> const&, const int*>());
#else // ^^^ C++23 / C++20 vvv
STATIC_ASSERT(test_cbegin<std::span<int> const&, std::span<int>::iterator>());
STATIC_ASSERT(test_cend<std::span<int> const&, std::span<int>::iterator>());
STATIC_ASSERT(test_crbegin<std::span<int> const&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_crend<std::span<int> const&, std::reverse_iterator<std::span<int>::iterator>>());
STATIC_ASSERT(test_cdata<std::span<int> const&, int*>());
#endif // C++20
using valarray_int_iterator = decltype(std::begin(std::declval<std::valarray<int>&>()));
using const_valarray_int_iterator = decltype(std::begin(std::declval<const std::valarray<int>&>()));
STATIC_ASSERT(test_begin<std::valarray<int>>());

Просмотреть файл

@ -95,6 +95,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(!CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(!CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(!CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(!CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -116,6 +122,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(!CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(!CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(!CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(!CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -137,6 +149,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(!CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(!CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -158,6 +176,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(!CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(!CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -179,6 +203,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(!CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(!CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -200,6 +230,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(!CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(!CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -221,6 +257,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -242,6 +284,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -263,6 +311,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -284,6 +338,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -305,6 +365,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -326,6 +392,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -347,6 +419,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -368,6 +446,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -389,6 +473,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -410,6 +500,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -431,6 +527,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -452,6 +554,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -473,6 +581,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -494,6 +608,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -515,6 +635,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -536,6 +662,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -557,6 +689,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -578,6 +716,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -599,6 +743,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -620,6 +770,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -641,6 +797,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -662,6 +824,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
@ -683,6 +851,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(CanData<V&>);
@ -704,6 +878,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(CanData<V&>);
@ -725,6 +905,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(!CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(!CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(CanData<V&>);
@ -746,6 +932,12 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
#if _HAS_CXX23
STATIC_ASSERT(CanMemberCBegin<V&>);
STATIC_ASSERT(CanMemberCBegin<V const&>);
STATIC_ASSERT(CanMemberCEnd<V&>);
STATIC_ASSERT(CanMemberCEnd<V const&>);
#endif // _HAS_CXX23
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(CanData<V&>);

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\concepts_latest_matrix.lst

Просмотреть файл

@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <cassert>
#include <concepts>
#include <iterator>
#include <span>
#include <type_traits>
#include <utility>
using namespace std;
enum class Const : bool { no, yes };
enum class Dynamic : bool { no, yes };
static_assert(!to_underlying(Const::no) && to_underlying(Const::yes));
static_assert(!to_underlying(Dynamic::no) && to_underlying(Dynamic::yes));
template <Const IsConst, Dynamic IsDynamic>
constexpr bool test() {
using T = conditional_t<to_underlying(IsConst), const int, int>;
using Span = span<T, to_underlying(IsDynamic) ? dynamic_extent : 3>;
using CIt = typename Span::const_iterator;
using CRevIt = typename Span::const_reverse_iterator;
// Validate iterator properties
static_assert(contiguous_iterator<CIt>);
static_assert(random_access_iterator<CRevIt>);
static_assert(same_as<CIt, const_iterator<typename Span::iterator>>);
static_assert(same_as<CRevIt, const_iterator<typename Span::reverse_iterator>>);
static_assert(same_as<CIt, const_iterator<CIt>>);
static_assert(same_as<CRevIt, const_iterator<CRevIt>>);
static_assert(same_as<iter_value_t<CIt>, remove_cv_t<T>>);
static_assert(same_as<iter_value_t<CRevIt>, remove_cv_t<T>>);
static_assert(same_as<iter_reference_t<CIt>, const T&>);
static_assert(same_as<iter_reference_t<CRevIt>, const T&>);
T elems[3] = {1, 22, 333};
const Span s{elems};
{ // Validate span::cbegin
same_as<CIt> auto it = s.cbegin();
assert(it == s.begin());
assert(*it == 1);
static_assert(noexcept(s.cbegin()));
}
{ // Validate span::cend
same_as<CIt> auto it = s.cend();
assert(it == s.end());
assert(it[-1] == 333);
static_assert(noexcept(s.cend()));
}
{ // Validate span::crbegin
same_as<CRevIt> auto it = s.crbegin();
assert(it == s.rbegin());
assert(*it == 333);
static_assert(noexcept(s.crbegin()));
}
{ // Validate span::crend
same_as<CRevIt> auto it = s.crend();
assert(it == s.rend());
assert(it[-1] == 1);
static_assert(noexcept(s.crend()));
}
return true;
}
int main() {
static_assert(test<Const::no, Dynamic::no>());
static_assert(test<Const::yes, Dynamic::no>());
static_assert(test<Const::no, Dynamic::yes>());
static_assert(test<Const::yes, Dynamic::yes>());
test<Const::no, Dynamic::no>();
test<Const::yes, Dynamic::no>();
test<Const::no, Dynamic::yes>();
test<Const::yes, Dynamic::yes>();
}

Просмотреть файл

@ -12,16 +12,16 @@
using namespace std;
template <typename It>
template <class It>
concept CanIterConstRef = requires { typename iter_const_reference_t<It>; };
template <typename It>
template <class It>
concept CanConstIterator = requires(It it) {
typename const_iterator<It>;
{ make_const_iterator(move(it)) } -> same_as<const_iterator<It>>;
};
template <typename Se>
template <class Se>
concept CanConstSentinel = requires(Se se) {
typename const_sentinel<Se>;
{ make_const_sentinel(move(se)) } -> same_as<const_sentinel<Se>>;

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\concepts_latest_matrix.lst

Просмотреть файл

@ -0,0 +1,240 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <cassert>
#include <concepts>
#include <deque>
#include <forward_list>
#include <istream>
#include <list>
#include <ranges>
#include <type_traits>
#include <vector>
#include <range_algorithm_support.hpp>
// New members (cbegin and cend) of `view_interface` are tested in `P0896R4_ranges_subrange\test.cpp`.
// Updated CPOs (cbegin, cdata, ...) are tested in `P0896R4_ranges_range_machinery\test.cpp`
using namespace std;
template <class Rng>
concept CanRangeConstIterator = requires { typename ranges::const_iterator_t<Rng>; };
template <class Rng>
concept CanRangeConstSentinel = requires { typename ranges::const_sentinel_t<Rng>; };
template <class Rng>
concept CanRangeConstReference = requires { typename ranges::range_const_reference_t<Rng>; };
static_assert(!CanRangeConstIterator<void*>);
static_assert(!CanRangeConstSentinel<void*>);
static_assert(!CanRangeConstReference<void*>);
namespace test_array {
using Arr = int[10];
static_assert(CanRangeConstIterator<Arr>);
static_assert(CanRangeConstSentinel<Arr>);
static_assert(CanRangeConstReference<Arr>);
static_assert(same_as<ranges::const_iterator_t<Arr>, const_iterator<int*>>);
static_assert(same_as<ranges::const_sentinel_t<Arr>, const_iterator<int*>>);
static_assert(same_as<ranges::range_const_reference_t<Arr>, const int&>);
static_assert(!ranges::constant_range<Arr>);
using ConstArr = const Arr;
static_assert(CanRangeConstIterator<ConstArr>);
static_assert(CanRangeConstSentinel<ConstArr>);
static_assert(CanRangeConstReference<ConstArr>);
static_assert(same_as<ranges::const_iterator_t<ConstArr>, const int*>);
static_assert(same_as<ranges::const_sentinel_t<ConstArr>, const int*>);
static_assert(same_as<ranges::range_const_reference_t<ConstArr>, const int&>);
static_assert(ranges::constant_range<ConstArr>);
} // namespace test_array
namespace test_random_access_range {
using Rng = deque<int>;
static_assert(CanRangeConstIterator<Rng>);
static_assert(CanRangeConstSentinel<Rng>);
static_assert(CanRangeConstReference<Rng>);
static_assert(same_as<ranges::const_iterator_t<Rng>, const_iterator<Rng::iterator>>);
static_assert(same_as<ranges::const_sentinel_t<Rng>, const_iterator<Rng::iterator>>);
static_assert(same_as<ranges::range_const_reference_t<Rng>, const int&>);
static_assert(!ranges::constant_range<Rng>);
using ConstRng = const deque<int>;
static_assert(CanRangeConstIterator<ConstRng>);
static_assert(CanRangeConstSentinel<ConstRng>);
static_assert(CanRangeConstReference<ConstRng>);
static_assert(same_as<ranges::const_iterator_t<ConstRng>, ConstRng::const_iterator>);
static_assert(same_as<ranges::const_sentinel_t<ConstRng>, ConstRng::const_iterator>);
static_assert(same_as<ranges::range_const_reference_t<ConstRng>, const int&>);
static_assert(ranges::constant_range<ConstRng>);
} // namespace test_random_access_range
namespace test_bidirectional_range {
using Rng = list<int>;
static_assert(CanRangeConstIterator<Rng>);
static_assert(CanRangeConstSentinel<Rng>);
static_assert(CanRangeConstReference<Rng>);
static_assert(same_as<ranges::const_iterator_t<Rng>, const_iterator<Rng::iterator>>);
static_assert(same_as<ranges::const_sentinel_t<Rng>, const_iterator<Rng::iterator>>);
static_assert(same_as<ranges::range_const_reference_t<Rng>, const int&>);
static_assert(!ranges::constant_range<Rng>);
using ConstRng = const list<int>;
static_assert(CanRangeConstIterator<ConstRng>);
static_assert(CanRangeConstSentinel<ConstRng>);
static_assert(CanRangeConstReference<ConstRng>);
static_assert(same_as<ranges::const_iterator_t<ConstRng>, ConstRng::const_iterator>);
static_assert(same_as<ranges::const_sentinel_t<ConstRng>, ConstRng::const_iterator>);
static_assert(same_as<ranges::range_const_reference_t<ConstRng>, const int&>);
static_assert(ranges::constant_range<ConstRng>);
} // namespace test_bidirectional_range
namespace test_forward_range {
using Rng = forward_list<int>;
static_assert(CanRangeConstIterator<Rng>);
static_assert(CanRangeConstSentinel<Rng>);
static_assert(CanRangeConstReference<Rng>);
static_assert(same_as<ranges::const_iterator_t<Rng>, const_iterator<Rng::iterator>>);
static_assert(same_as<ranges::const_sentinel_t<Rng>, const_iterator<Rng::iterator>>);
static_assert(same_as<ranges::range_const_reference_t<Rng>, const int&>);
static_assert(!ranges::constant_range<Rng>);
using ConstRng = const forward_list<int>;
static_assert(CanRangeConstIterator<ConstRng>);
static_assert(CanRangeConstSentinel<ConstRng>);
static_assert(CanRangeConstReference<ConstRng>);
static_assert(same_as<ranges::const_iterator_t<ConstRng>, ConstRng::const_iterator>);
static_assert(same_as<ranges::const_sentinel_t<ConstRng>, ConstRng::const_iterator>);
static_assert(same_as<ranges::range_const_reference_t<ConstRng>, const int&>);
static_assert(ranges::constant_range<ConstRng>);
} // namespace test_forward_range
namespace test_input_range {
using Rng = ranges::istream_view<int>;
static_assert(CanRangeConstIterator<Rng>);
static_assert(CanRangeConstSentinel<Rng>);
static_assert(CanRangeConstReference<Rng>);
static_assert(same_as<ranges::const_iterator_t<Rng>, const_iterator<ranges::iterator_t<Rng>>>);
static_assert(same_as<ranges::const_sentinel_t<Rng>, default_sentinel_t>);
static_assert(same_as<ranges::range_const_reference_t<Rng>, const int&>);
static_assert(!ranges::constant_range<Rng>);
} // namespace test_input_range
namespace test_prvalue_range {
using Rng = ranges::transform_view<ranges::ref_view<deque<float>>, int (*)(float)>;
static_assert(CanRangeConstIterator<Rng>);
static_assert(CanRangeConstSentinel<Rng>);
static_assert(CanRangeConstReference<Rng>);
static_assert(same_as<ranges::const_iterator_t<Rng>, const_iterator<ranges::iterator_t<Rng>>>);
static_assert(same_as<ranges::const_sentinel_t<Rng>, const_iterator<ranges::iterator_t<Rng>>>);
static_assert(same_as<ranges::range_const_reference_t<Rng>, int>);
static_assert(ranges::constant_range<Rng>);
using ConstRng = const Rng;
static_assert(CanRangeConstIterator<ConstRng>);
static_assert(CanRangeConstSentinel<ConstRng>);
static_assert(CanRangeConstReference<ConstRng>);
static_assert(same_as<ranges::const_iterator_t<ConstRng>, const_iterator<ranges::iterator_t<ConstRng>>>);
static_assert(same_as<ranges::const_sentinel_t<ConstRng>, const_iterator<ranges::iterator_t<ConstRng>>>);
static_assert(same_as<ranges::range_const_reference_t<ConstRng>, int>);
static_assert(ranges::constant_range<ConstRng>);
} // namespace test_prvalue_range
namespace test_vector_bool {
using Vb = vector<bool>;
static_assert(CanRangeConstIterator<Vb>);
static_assert(CanRangeConstSentinel<Vb>);
static_assert(CanRangeConstReference<Vb>);
static_assert(same_as<ranges::const_iterator_t<Vb>, const_iterator<Vb::iterator>>);
static_assert(same_as<ranges::const_sentinel_t<Vb>, const_iterator<Vb::iterator>>);
static_assert(same_as<ranges::range_const_reference_t<Vb>, bool>);
static_assert(!ranges::constant_range<Vb>);
using ConstVb = const vector<bool>;
static_assert(CanRangeConstIterator<ConstVb>);
static_assert(CanRangeConstSentinel<ConstVb>);
static_assert(CanRangeConstReference<ConstVb>);
static_assert(same_as<ranges::const_iterator_t<ConstVb>, ConstVb::const_iterator>);
static_assert(same_as<ranges::const_sentinel_t<ConstVb>, ConstVb::const_iterator>);
static_assert(same_as<ranges::range_const_reference_t<ConstVb>, bool>);
static_assert(ranges::constant_range<ConstVb>);
} // namespace test_vector_bool
template <class Rng>
static constexpr void test_cpos(Rng&& rng) {
using ranges::iterator_t, ranges::sentinel_t;
using R = conditional_t<ranges::constant_range<const Rng&> && !ranges::constant_range<Rng&>, const Rng&, Rng&>;
{ // Validate ranges::cbegin
using It = iterator_t<R>;
const same_as<const_iterator<It>> auto it = ranges::cbegin(rng);
if constexpr (equality_comparable<It>) {
if (ranges::forward_range<Rng>) { // intentionally not if constexpr
assert(it == ranges::begin(rng));
}
}
static_assert(noexcept(ranges::cbegin(rng))
== (noexcept(ranges::begin(rng)) && is_nothrow_constructible_v<const_iterator<It>, It>) );
}
{ // Validate ranges::cend
using Se = sentinel_t<R>;
const same_as<const_sentinel<Se>> auto se = ranges::cend(rng);
if constexpr (equality_comparable<Se>) {
assert(se == ranges::end(rng));
}
static_assert(noexcept(ranges::cend(rng))
== (noexcept(ranges::end(rng)) && is_nothrow_constructible_v<const_sentinel<Se>, Se>) );
}
if constexpr (ranges::bidirectional_range<Rng>) {
if constexpr (CanRBegin<Rng>) { // Validate ranges::crbegin
using RevIt = decltype(ranges::rbegin(declval<R&>()));
const same_as<const_iterator<RevIt>> auto it = ranges::crbegin(rng);
assert(it == ranges::rbegin(rng));
static_assert(
noexcept(ranges::crbegin(rng))
== (noexcept(ranges::rbegin(rng)) && is_nothrow_constructible_v<const_iterator<RevIt>, RevIt>) );
}
if constexpr (CanREnd<Rng>) { // Validate ranges::crend
using RevSe = decltype(ranges::rend(declval<R&>()));
const same_as<const_sentinel<RevSe>> auto it = ranges::crend(rng);
assert(it == ranges::rend(rng));
static_assert(
noexcept(ranges::crend(rng))
== (noexcept(ranges::rend(rng)) && is_nothrow_constructible_v<const_sentinel<RevSe>, RevSe>) );
}
}
if constexpr (ranges::contiguous_range<Rng>) { // Validate ranges::cdata
const same_as<const ranges::range_value_t<Rng>*> auto ptr = ranges::cdata(rng);
assert(ptr == ranges::data(rng));
static_assert(noexcept(ranges::cdata(rng)) == noexcept(ranges::data(rng)));
}
}
struct instantiator {
template <class Rng>
static constexpr void call() {
int some_ints[] = {1, 2, 3};
Rng rng{some_ints};
test_cpos(rng);
}
};
int main() {
STATIC_ASSERT((test_in<instantiator, const int>(), true));
test_in<instantiator, const int>();
}