зеркало из https://github.com/microsoft/STL.git
P2387R3 Pipe for user defined range adaptors (#2661)
Co-authored-by: nicole mazzuca <mazzucan@outlook.com> Co-authored-by: Casey Carter <Casey@Carter.net> Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
Родитель
22d6408f24
Коммит
2ae879b73c
|
@ -619,6 +619,14 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="std::_Back_binder<*>">
|
||||
<DisplayString>bind_back({_Mypair}, {_Mypair._Myval2,view(noparens)})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[f]">_Mypair</Item>
|
||||
<Item Name="[bound_args]">_Mypair._Myval2</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
|
||||
<!-- VC 2015 -->
|
||||
<Type Name="std::_Mem_fn<*>">
|
||||
|
|
|
@ -2130,6 +2130,83 @@ _NODISCARD constexpr auto bind_front(_Fx&& _Func, _Types&&... _Args) {
|
|||
}
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
#if _HAS_CXX23
|
||||
template <size_t... _Ix, class _Cv_FD, class _Cv_tuple_TiD, class... _Unbound>
|
||||
constexpr auto _Call_back_binder(index_sequence<_Ix...>, _Cv_FD&& _Obj, _Cv_tuple_TiD&& _Tpl,
|
||||
_Unbound&&... _Unbargs) noexcept(noexcept(_STD invoke(_STD forward<_Cv_FD>(_Obj),
|
||||
_STD forward<_Unbound>(_Unbargs)..., _STD get<_Ix>(_STD forward<_Cv_tuple_TiD>(_Tpl))...)))
|
||||
-> decltype(_STD invoke(_STD forward<_Cv_FD>(_Obj), _STD forward<_Unbound>(_Unbargs)...,
|
||||
_STD get<_Ix>(_STD forward<_Cv_tuple_TiD>(_Tpl))...)) {
|
||||
return _STD invoke(_STD forward<_Cv_FD>(_Obj), _STD forward<_Unbound>(_Unbargs)...,
|
||||
_STD get<_Ix>(_STD forward<_Cv_tuple_TiD>(_Tpl))...);
|
||||
}
|
||||
|
||||
template <class _Fx, class... _Types>
|
||||
class _Back_binder { // wrap bound callable object and arguments
|
||||
private:
|
||||
using _Seq = index_sequence_for<_Types...>;
|
||||
|
||||
_Compressed_pair<_Fx, tuple<_Types...>> _Mypair;
|
||||
|
||||
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Fx, decay_t<_Fx>>);
|
||||
_STL_INTERNAL_STATIC_ASSERT((is_same_v<_Types, decay_t<_Types>> && ...));
|
||||
|
||||
public:
|
||||
template <class _FxInit, class... _TypesInit,
|
||||
enable_if_t<sizeof...(_TypesInit) != 0 || !is_same_v<remove_cvref_t<_FxInit>, _Back_binder>, int> = 0>
|
||||
constexpr explicit _Back_binder(_FxInit&& _Func, _TypesInit&&... _Args)
|
||||
: _Mypair(_One_then_variadic_args_t{}, _STD forward<_FxInit>(_Func), _STD forward<_TypesInit>(_Args)...) {}
|
||||
|
||||
template <class... _Unbound>
|
||||
constexpr auto operator()(_Unbound&&... _Unbargs) & noexcept(
|
||||
noexcept(_Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)))
|
||||
-> decltype(_Call_back_binder(
|
||||
_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)) {
|
||||
return _Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...);
|
||||
}
|
||||
|
||||
template <class... _Unbound>
|
||||
constexpr auto operator()(_Unbound&&... _Unbargs) const& noexcept(
|
||||
noexcept(_Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)))
|
||||
-> decltype(_Call_back_binder(
|
||||
_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)) {
|
||||
return _Call_back_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...);
|
||||
}
|
||||
|
||||
template <class... _Unbound>
|
||||
constexpr auto operator()(_Unbound&&... _Unbargs) && noexcept(noexcept(_Call_back_binder(
|
||||
_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)))
|
||||
-> decltype(_Call_back_binder(
|
||||
_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)) {
|
||||
return _Call_back_binder(
|
||||
_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...);
|
||||
}
|
||||
|
||||
template <class... _Unbound>
|
||||
constexpr auto operator()(_Unbound&&... _Unbargs) const&& noexcept(noexcept(_Call_back_binder(
|
||||
_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)))
|
||||
-> decltype(_Call_back_binder(
|
||||
_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)) {
|
||||
return _Call_back_binder(
|
||||
_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class _Fx, class... _Types>
|
||||
_NODISCARD constexpr auto bind_back(_Fx&& _Func, _Types&&... _Args) {
|
||||
static_assert(is_constructible_v<decay_t<_Fx>, _Fx>,
|
||||
"std::bind_back requires the decayed callable to be constructible from an undecayed callable");
|
||||
static_assert(
|
||||
is_move_constructible_v<decay_t<_Fx>>, "std::bind_back requires the decayed callable to be move constructible");
|
||||
static_assert(conjunction_v<is_constructible<decay_t<_Types>, _Types>...>,
|
||||
"std::bind_back requires the decayed bound arguments to be constructible from undecayed bound arguments");
|
||||
static_assert(conjunction_v<is_move_constructible<decay_t<_Types>>...>,
|
||||
"std::bind_back requires the decayed bound arguments to be move constructible");
|
||||
|
||||
return _Back_binder<decay_t<_Fx>, decay_t<_Types>...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
|
||||
}
|
||||
#endif // _HAS_CXX23
|
||||
|
||||
#if _HAS_FUNCTION_ALLOCATOR_SUPPORT
|
||||
template <class _Fty, class _Alloc>
|
||||
struct uses_allocator<function<_Fty>, _Alloc> : true_type {}; // true_type if container allocator enabled
|
||||
|
|
154
stl/inc/ranges
154
stl/inc/ranges
|
@ -61,108 +61,80 @@ namespace ranges {
|
|||
using _Maybe_wrapped = conditional_t<_IsWrapped, _Ty, _Unwrapped_t<_Ty>>;
|
||||
|
||||
namespace _Pipe {
|
||||
// clang-format off
|
||||
template <class _Left, class _Right>
|
||||
concept _Can_pipe = requires(_Left&& __l, _Right&& __r) {
|
||||
static_cast<_Right&&>(__r)(static_cast<_Left&&>(__l));
|
||||
};
|
||||
|
||||
template <class _Left, class _Right>
|
||||
concept _Can_compose = constructible_from<remove_cvref_t<_Left>, _Left>
|
||||
&& constructible_from<remove_cvref_t<_Right>, _Right>;
|
||||
// clang-format on
|
||||
|
||||
template <class, class>
|
||||
struct _Pipeline;
|
||||
|
||||
template <class _Derived>
|
||||
struct _Base {
|
||||
template <class _Other>
|
||||
requires _Can_compose<_Derived, _Other>
|
||||
constexpr auto operator|(_Base<_Other>&& __r) && noexcept(
|
||||
noexcept(_Pipeline{static_cast<_Derived&&>(*this), static_cast<_Other&&>(__r)})) {
|
||||
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
|
||||
return _Pipeline{static_cast<_Derived&&>(*this), static_cast<_Other&&>(__r)};
|
||||
}
|
||||
struct _Base {};
|
||||
|
||||
template <class _Other>
|
||||
requires _Can_compose<_Derived, const _Other&>
|
||||
constexpr auto operator|(const _Base<_Other>& __r) && noexcept(
|
||||
noexcept(_Pipeline{static_cast<_Derived&&>(*this), static_cast<const _Other&>(__r)})) {
|
||||
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
|
||||
return _Pipeline{static_cast<_Derived&&>(*this), static_cast<const _Other&>(__r)};
|
||||
}
|
||||
template <class _Ty>
|
||||
_Ty* _Derived_from_range_adaptor_closure(_Base<_Ty>&); // not defined
|
||||
|
||||
template <class _Other>
|
||||
requires _Can_compose<const _Derived&, _Other>
|
||||
constexpr auto operator|(_Base<_Other>&& __r) const& noexcept(
|
||||
noexcept(_Pipeline{static_cast<const _Derived&>(*this), static_cast<_Other&&>(__r)})) {
|
||||
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
|
||||
return _Pipeline{static_cast<const _Derived&>(*this), static_cast<_Other&&>(__r)};
|
||||
}
|
||||
|
||||
template <class _Other>
|
||||
requires _Can_compose<const _Derived&, const _Other&>
|
||||
constexpr auto operator|(const _Base<_Other>& __r) const& noexcept(
|
||||
noexcept(_Pipeline{static_cast<const _Derived&>(*this), static_cast<const _Other&>(__r)})) {
|
||||
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
|
||||
return _Pipeline{static_cast<const _Derived&>(*this), static_cast<const _Other&>(__r)};
|
||||
}
|
||||
|
||||
template <_Can_pipe<const _Derived&> _Left>
|
||||
friend constexpr auto operator|(_Left&& __l, const _Base& __r)
|
||||
#ifdef __EDG__ // TRANSITION, VSO-1222776
|
||||
noexcept(noexcept(_STD declval<const _Derived&>()(_STD forward<_Left>(__l))))
|
||||
#else // ^^^ workaround / no workaround vvv
|
||||
noexcept(noexcept(static_cast<const _Derived&>(__r)(_STD forward<_Left>(__l))))
|
||||
#endif // TRANSITION, VSO-1222776
|
||||
{
|
||||
return static_cast<const _Derived&>(__r)(_STD forward<_Left>(__l));
|
||||
}
|
||||
|
||||
template <_Can_pipe<_Derived> _Left>
|
||||
friend constexpr auto operator|(_Left&& __l, _Base&& __r)
|
||||
#ifdef __EDG__ // TRANSITION, VSO-1222776
|
||||
noexcept(noexcept(_STD declval<_Derived>()(_STD forward<_Left>(__l))))
|
||||
#else // ^^^ workaround / no workaround vvv
|
||||
noexcept(noexcept(static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l))))
|
||||
#endif // TRANSITION, VSO-1222776
|
||||
{
|
||||
return static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l));
|
||||
}
|
||||
template <class _Ty>
|
||||
concept _Range_adaptor_closure_object = !range<remove_cvref_t<_Ty>> && requires(remove_cvref_t<_Ty> & __t) {
|
||||
{ _Pipe::_Derived_from_range_adaptor_closure(__t) } -> same_as<remove_cvref_t<_Ty>*>;
|
||||
};
|
||||
|
||||
template <class _Left, class _Right>
|
||||
struct _Pipeline : _Base<_Pipeline<_Left, _Right>> {
|
||||
/* [[no_unique_address]] */ _Left __l;
|
||||
/* [[no_unique_address]] */ _Right __r;
|
||||
template <class _ClosureLeft, class _ClosureRight>
|
||||
struct _Pipeline : _Base<_Pipeline<_ClosureLeft, _ClosureRight>> {
|
||||
_STL_INTERNAL_STATIC_ASSERT(_Range_adaptor_closure_object<_ClosureLeft>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(_Range_adaptor_closure_object<_ClosureRight>);
|
||||
|
||||
/* [[no_unique_address]] */ _ClosureLeft _Left;
|
||||
/* [[no_unique_address]] */ _ClosureRight _Right;
|
||||
|
||||
template <class _Ty1, class _Ty2>
|
||||
constexpr explicit _Pipeline(_Ty1&& _Val1, _Ty2&& _Val2) noexcept(
|
||||
is_nothrow_convertible_v<_Ty1, _Left>&& is_nothrow_convertible_v<_Ty2, _Right>)
|
||||
: __l(_STD forward<_Ty1>(_Val1)), __r(_STD forward<_Ty2>(_Val2)) {}
|
||||
is_nothrow_constructible_v<_Ty1, _ClosureLeft>&& is_nothrow_constructible_v<_Ty2, _ClosureRight>)
|
||||
: _Left(_STD forward<_Ty1>(_Val1)), _Right(_STD forward<_Ty2>(_Val2)) {}
|
||||
|
||||
template <class _Ty>
|
||||
_NODISCARD constexpr auto operator()(_Ty&& _Val) noexcept(
|
||||
noexcept(__r(__l(_STD forward<_Ty>(_Val))))) requires requires {
|
||||
__r(__l(static_cast<_Ty&&>(_Val)));
|
||||
_NODISCARD constexpr auto operator()(_Ty&& _Val) & noexcept(
|
||||
noexcept(_Right(_Left(_STD forward<_Ty>(_Val))))) requires requires {
|
||||
_Right(_Left(_STD forward<_Ty>(_Val)));
|
||||
}
|
||||
{ return __r(__l(_STD forward<_Ty>(_Val))); }
|
||||
{ return _Right(_Left(_STD forward<_Ty>(_Val))); }
|
||||
|
||||
template <class _Ty>
|
||||
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
|
||||
noexcept(noexcept(__r(__l(_STD forward<_Ty>(_Val))))) requires requires {
|
||||
__r(__l(static_cast<_Ty&&>(_Val)));
|
||||
_NODISCARD constexpr auto operator()(_Ty&& _Val) const& noexcept(
|
||||
noexcept(_Right(_Left(_STD forward<_Ty>(_Val))))) requires requires {
|
||||
_Right(_Left(_STD forward<_Ty>(_Val)));
|
||||
}
|
||||
{ return __r(__l(_STD forward<_Ty>(_Val))); }
|
||||
{ return _Right(_Left(_STD forward<_Ty>(_Val))); }
|
||||
|
||||
template <class _Ty>
|
||||
_NODISCARD constexpr auto operator()(_Ty&& _Val) && noexcept(
|
||||
noexcept(_STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val))))) requires requires {
|
||||
_STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val)));
|
||||
}
|
||||
{ return _STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val))); }
|
||||
|
||||
template <class _Ty>
|
||||
_NODISCARD constexpr auto operator()(_Ty&& _Val) const&& noexcept(
|
||||
noexcept(_STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val))))) requires requires {
|
||||
_STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val)));
|
||||
}
|
||||
{ return _STD move(_Right)(_STD move(_Left)(_STD forward<_Ty>(_Val))); }
|
||||
};
|
||||
|
||||
template <class _Ty1, class _Ty2>
|
||||
_Pipeline(_Ty1, _Ty2) -> _Pipeline<_Ty1, _Ty2>;
|
||||
|
||||
template <class _Left, class _Right>
|
||||
requires _Range_adaptor_closure_object<_Left> //
|
||||
&& _Range_adaptor_closure_object<_Right> //
|
||||
&& constructible_from<remove_cvref_t<_Left>, _Left> //
|
||||
&& constructible_from<remove_cvref_t<_Right>, _Right> //
|
||||
_NODISCARD constexpr auto operator|(_Left&& __l, _Right&& __r) noexcept(
|
||||
noexcept(_Pipeline{static_cast<_Left&&>(__l), static_cast<_Right&&>(__r)})) {
|
||||
return _Pipeline{static_cast<_Left&&>(__l), static_cast<_Right&&>(__r)};
|
||||
}
|
||||
|
||||
template <class _Left, class _Right>
|
||||
requires _Range_adaptor_closure_object<_Right> && range<_Left> //
|
||||
_NODISCARD constexpr auto operator|(_Left&& __l, _Right&& __r) noexcept(
|
||||
noexcept(_STD forward<_Right>(__r)(_STD forward<_Left>(__l)))) //
|
||||
requires requires {
|
||||
static_cast<_Right&&>(__r)(static_cast<_Left&&>(__l));
|
||||
}
|
||||
{ return _STD forward<_Right>(__r)(_STD forward<_Left>(__l)); }
|
||||
} // namespace _Pipe
|
||||
|
||||
template <range _Rng, class _Derived>
|
||||
|
@ -805,6 +777,13 @@ namespace ranges {
|
|||
};
|
||||
};
|
||||
|
||||
#if _HAS_CXX23
|
||||
template <class _Derived>
|
||||
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
|
||||
class range_adaptor_closure : public _Pipe::_Base<_Derived> {
|
||||
};
|
||||
#endif // _HAS_CXX23
|
||||
|
||||
template <class _Fn, class... _Types>
|
||||
class _Range_closure : public _Pipe::_Base<_Range_closure<_Fn, _Types...>> {
|
||||
public:
|
||||
|
@ -4289,7 +4268,6 @@ namespace ranges {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
using iterator_concept = typename _Outer_iter<_Const>::iterator_concept;
|
||||
using value_type = range_value_t<_BaseTy>;
|
||||
|
@ -4506,7 +4484,7 @@ namespace ranges {
|
|||
#else // ^^^ no workaround / workaround vvv
|
||||
auto _Match = _RANGES search(subrange{_Current, _Last}, _Parent->_Pattern);
|
||||
auto _Begin = _Match.begin();
|
||||
auto _End = _Match.end();
|
||||
auto _End = _Match.end();
|
||||
#endif // TRANSITION, DevCom-1559808
|
||||
if (_Begin != _Last && _RANGES empty(_Parent->_Pattern)) {
|
||||
++_Begin;
|
||||
|
@ -4558,7 +4536,7 @@ namespace ranges {
|
|||
#else // ^^^ no workaround / workaround vvv
|
||||
auto _Match = _RANGES search(subrange{_It, _Last}, _Pattern);
|
||||
auto _Begin = _Match.begin();
|
||||
auto _End = _Match.end();
|
||||
auto _End = _Match.end();
|
||||
#endif // TRANSITION, DevCom-1559808
|
||||
if (_Begin != _Last && _RANGES empty(_Pattern)) {
|
||||
++_Begin;
|
||||
|
@ -5086,7 +5064,7 @@ namespace ranges {
|
|||
(void) _Off;
|
||||
#else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 / _ITERATOR_DEBUG_LEVEL != 0 vvv
|
||||
if constexpr (_Offset_verifiable_v<iterator_t<_Base>>) {
|
||||
_Current._Verify_offset(_Off);
|
||||
_Current._Verify_offset(_Off);
|
||||
}
|
||||
#endif // _ITERATOR_DEBUG_LEVEL == 0
|
||||
}
|
||||
|
|
|
@ -323,6 +323,7 @@
|
|||
// P2302R4 ranges::contains, ranges::contains_subrange
|
||||
// P2321R2 zip
|
||||
// (changes to pair, tuple, and vector<bool>::reference only)
|
||||
// P2387R3 Pipe Support For User-Defined Range Adaptors
|
||||
// P2417R2 More constexpr bitset
|
||||
// P2440R1 ranges::iota, ranges::shift_left, ranges::shift_right
|
||||
// P2441R2 views::join_with
|
||||
|
@ -1459,10 +1460,6 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
|
|||
|
||||
#define __cpp_lib_polymorphic_allocator 201902L
|
||||
|
||||
#ifdef __cpp_lib_concepts // TRANSITION, GH-395
|
||||
#define __cpp_lib_ranges 202110L
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
#define __cpp_lib_remove_cvref 201711L
|
||||
#define __cpp_lib_semaphore 201907L
|
||||
#define __cpp_lib_smart_ptr_for_overwrite 202002L
|
||||
|
@ -1495,6 +1492,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
|
|||
#endif // __cpp_lib_concepts
|
||||
|
||||
#define __cpp_lib_associative_heterogeneous_erasure 202110L
|
||||
#define __cpp_lib_bind_back 202202L
|
||||
#define __cpp_lib_byteswap 202110L
|
||||
#define __cpp_lib_constexpr_bitset 202207L
|
||||
#define __cpp_lib_constexpr_typeinfo 202106L
|
||||
|
@ -1569,6 +1567,14 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
|
|||
#define __cpp_lib_optional 201606L // P0307R2 Making Optional Greater Equal Again
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#if defined(__cpp_lib_concepts) // TRANSITION, GH-395
|
||||
#if _HAS_CXX23
|
||||
#define __cpp_lib_ranges 202202L // P2387R3 Pipe Support For User-Defined Range Adaptors
|
||||
#elif _HAS_CXX20 // ^^^ _HAS_CXX23 / _HAS_CXX20 vvv
|
||||
#define __cpp_lib_ranges 202110L // P2415R2 What Is A `view`?
|
||||
#endif // _HAS_CXX20
|
||||
#endif // defined(__cpp_lib_concepts)
|
||||
|
||||
#if _HAS_CXX20
|
||||
#define __cpp_lib_shared_ptr_arrays 201707L // P0674R1 make_shared() For Arrays
|
||||
#else // _HAS_CXX20
|
||||
|
|
|
@ -543,6 +543,8 @@ tests\P2273R3_constexpr_unique_ptr
|
|||
tests\P2302R4_ranges_alg_contains
|
||||
tests\P2302R4_ranges_alg_contains_subrange
|
||||
tests\P2321R2_proxy_reference
|
||||
tests\P2387R3_bind_back
|
||||
tests\P2387R3_pipe_support_for_user_defined_range_adaptors
|
||||
tests\P2401R0_conditional_noexcept_for_exchange
|
||||
tests\P2408R5_ranges_iterators_to_classic_algorithms
|
||||
tests\P2415R2_owning_view
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\usual_latest_matrix.lst
|
|
@ -0,0 +1,216 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
|
||||
constexpr int f0() {
|
||||
return 1729;
|
||||
}
|
||||
|
||||
constexpr int f1(int x) {
|
||||
return x * 10;
|
||||
}
|
||||
|
||||
constexpr int f2(int x, int y) {
|
||||
return x * 100 + y * 10;
|
||||
}
|
||||
|
||||
constexpr int f3(int x, int y, int z) {
|
||||
return x * 1000 + y * 100 + z * 10;
|
||||
}
|
||||
|
||||
struct Cat {
|
||||
string name;
|
||||
};
|
||||
|
||||
struct CatNoise {
|
||||
string noise(const string& s, const Cat& cat) const {
|
||||
return cat.name + " says " + s;
|
||||
}
|
||||
};
|
||||
|
||||
struct DetectQualifiers {
|
||||
constexpr string_view operator()() & {
|
||||
return "modifiable lvalue";
|
||||
}
|
||||
|
||||
constexpr string_view operator()() const& {
|
||||
return "const lvalue";
|
||||
}
|
||||
|
||||
constexpr string_view operator()() && {
|
||||
return "modifiable rvalue";
|
||||
}
|
||||
|
||||
constexpr string_view operator()() const&& {
|
||||
return "const rvalue";
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool test_constexpr() {
|
||||
// Test varying numbers of arguments.
|
||||
assert(bind_back(f0)() == 1729);
|
||||
|
||||
assert(bind_back(f1)(2) == 20);
|
||||
assert(bind_back(f1, 3)() == 30);
|
||||
|
||||
assert(bind_back(f2)(4, 5) == 450);
|
||||
assert(bind_back(f2, 7)(6) == 670);
|
||||
assert(bind_back(f2, 8, 9)() == 890);
|
||||
|
||||
assert(bind_back(f3)(2, 3, 4) == 2340);
|
||||
assert(bind_back(f3, 4, 5)(3) == 3450);
|
||||
assert(bind_back(f3, 5, 6)(4) == 4560);
|
||||
assert(bind_back(f3, 5, 6, 7)() == 5670);
|
||||
|
||||
// Test function pointers.
|
||||
assert(bind_back(&f0)() == 1729);
|
||||
assert(bind_back(&f2, 7)(6) == 670);
|
||||
|
||||
// Test stateless lambdas.
|
||||
assert(bind_back([] { return 11; })() == 11);
|
||||
assert(bind_back([](int x, int y) { return x * 2 + y * 3; }, 10)(100) == 230);
|
||||
|
||||
// Test stateful lambdas.
|
||||
int value = 0;
|
||||
|
||||
auto bound0 = bind_back([&value] { ++value; });
|
||||
bound0();
|
||||
assert(value == 1);
|
||||
bound0();
|
||||
assert(value == 2);
|
||||
|
||||
auto bound1 = bind_back([&value](int x, int y) { value = value * x + y; }, 10);
|
||||
bound1(3);
|
||||
assert(value == 16);
|
||||
bound1(4);
|
||||
assert(value == 74);
|
||||
|
||||
// Test "perfect forwarding call wrapper" behavior.
|
||||
auto bound5 = bind_back(DetectQualifiers{});
|
||||
assert(bound5() == "modifiable lvalue");
|
||||
assert(as_const(bound5)() == "const lvalue");
|
||||
assert(move(bound5)() == "modifiable rvalue");
|
||||
assert(move(as_const(bound5))() == "const rvalue");
|
||||
|
||||
// Test decay when binding.
|
||||
const int arr[] = {11, 22, 33};
|
||||
const int three = 3;
|
||||
|
||||
auto bound8 = bind_back(
|
||||
[](auto&& a, auto&& f, auto&& i) {
|
||||
using FP = int (*)(int);
|
||||
return is_same_v<decltype(a), const int*&> && is_same_v<decltype(f), FP&> && is_same_v<decltype(i), int&>;
|
||||
},
|
||||
arr, f1, three);
|
||||
assert(bound8());
|
||||
|
||||
// Test forward when calling.
|
||||
auto bound9 = bind_back([](auto&& a1, auto&& a2, auto&& a3, auto&& a4) {
|
||||
constexpr bool same1 = is_same_v<decltype(a1), int&>;
|
||||
constexpr bool same2 = is_same_v<decltype(a2), const int&>;
|
||||
constexpr bool same3 = is_same_v<decltype(a3), int&&>;
|
||||
constexpr bool same4 = is_same_v<decltype(a4), const int&&>;
|
||||
return same1 && same2 && same3 && same4;
|
||||
});
|
||||
assert(bound9(value, three, 1729, move(three)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void test_move_only_types() {
|
||||
// Test movable-only types.
|
||||
auto unique_lambda = [up1 = make_unique<int>(1200)](unique_ptr<int>&& up2) {
|
||||
if (up1 && up2) {
|
||||
return make_unique<int>(*up1 + *up2);
|
||||
} else if (up1) {
|
||||
return make_unique<int>(*up1 * -1);
|
||||
} else if (up2) {
|
||||
return make_unique<int>(*up2 * -10);
|
||||
} else {
|
||||
return make_unique<int>(-9000);
|
||||
}
|
||||
};
|
||||
auto bound6 = bind_back(move(unique_lambda), make_unique<int>(34));
|
||||
assert(*unique_lambda(make_unique<int>(56)) == -560);
|
||||
assert(*move(bound6)() == 1234);
|
||||
auto bound7 = move(bound6);
|
||||
assert(*move(bound6)() == -9000);
|
||||
assert(*move(bound7)() == 1234);
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_constexpr());
|
||||
static_assert(test_constexpr());
|
||||
|
||||
test_move_only_types();
|
||||
|
||||
// Also test GH-1292 "bind_front violates [func.require]p8" in which the return type of bind_front inadvertently
|
||||
// depends on the value category and/or cv-qualification of its arguments.
|
||||
{
|
||||
struct S {
|
||||
int i = 42;
|
||||
};
|
||||
S s;
|
||||
auto lambda = [](S x) { return x.i; };
|
||||
auto returns_lambda = [=] { return lambda; };
|
||||
auto returns_const_lambda = [=]() -> const decltype(lambda) { return lambda; };
|
||||
auto returns_const_S = []() -> const S { return {}; };
|
||||
|
||||
using T = decltype(bind_back(lambda, s));
|
||||
static_assert(is_same_v<decltype(bind_back(lambda, move(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(lambda, S{})), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(move(lambda), s)), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(move(lambda), move(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(move(lambda), S{})), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(returns_lambda(), s)), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(returns_lambda(), move(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(returns_lambda(), S{})), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(lambda, as_const(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(lambda, move(as_const(s)))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(lambda, returns_const_S())), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(move(lambda), as_const(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(move(lambda), move(as_const(s)))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(move(lambda), returns_const_S())), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(returns_lambda(), as_const(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(returns_lambda(), move(as_const(s)))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(returns_lambda(), returns_const_S())), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(as_const(lambda), s)), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(as_const(lambda), move(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(as_const(lambda), S{})), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(move(as_const(lambda)), s)), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(move(as_const(lambda)), move(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(move(as_const(lambda)), S{})), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(returns_const_lambda(), s)), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(returns_const_lambda(), move(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(returns_const_lambda(), S{})), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(as_const(lambda), as_const(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(as_const(lambda), move(as_const(s)))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(as_const(lambda), returns_const_S())), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(move(as_const(lambda)), as_const(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(move(as_const(lambda)), move(as_const(s)))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(move(as_const(lambda)), returns_const_S())), T>);
|
||||
|
||||
static_assert(is_same_v<decltype(bind_back(returns_const_lambda(), as_const(s))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(returns_const_lambda(), move(as_const(s)))), T>);
|
||||
static_assert(is_same_v<decltype(bind_back(returns_const_lambda(), returns_const_S())), T>);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst
|
|
@ -0,0 +1,236 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
|
||||
template <class T>
|
||||
concept CanInstantiateRangeAdaptorClosure = requires {
|
||||
typename ranges::range_adaptor_closure<T>;
|
||||
};
|
||||
|
||||
class EmptyTestType {};
|
||||
class IncompleteTestType;
|
||||
|
||||
static_assert(CanInstantiateRangeAdaptorClosure<EmptyTestType>);
|
||||
static_assert(!CanInstantiateRangeAdaptorClosure<const EmptyTestType>);
|
||||
static_assert(!CanInstantiateRangeAdaptorClosure<volatile EmptyTestType>);
|
||||
static_assert(!CanInstantiateRangeAdaptorClosure<EmptyTestType&>);
|
||||
static_assert(!CanInstantiateRangeAdaptorClosure<int>);
|
||||
static_assert(CanInstantiateRangeAdaptorClosure<IncompleteTestType>);
|
||||
|
||||
template <class LHS, class RHS>
|
||||
concept CanPipe = requires(LHS lhs, RHS rhs) {
|
||||
forward<LHS>(lhs) | forward<RHS>(rhs);
|
||||
};
|
||||
|
||||
template <class LHS, class RHS, class Ret>
|
||||
concept CanPipe_R = requires(LHS lhs, RHS rhs) {
|
||||
{ forward<LHS>(lhs) | forward<RHS>(rhs) } -> same_as<Ret>;
|
||||
};
|
||||
|
||||
using TestRange = array<int, 1>;
|
||||
|
||||
template <class T>
|
||||
constexpr bool is_range_adaptor_closure() {
|
||||
return CanPipe<TestRange, T&> || CanPipe<TestRange, const T&> //
|
||||
|| CanPipe<TestRange, T&&> || CanPipe<TestRange, const T&&>;
|
||||
}
|
||||
|
||||
struct IdentityRangeAdaptorClosure : ranges::range_adaptor_closure<IdentityRangeAdaptorClosure> {
|
||||
template <class T>
|
||||
constexpr decltype(auto) operator()(T&& range) const {
|
||||
return forward<T>(range);
|
||||
}
|
||||
};
|
||||
|
||||
// Is not a range adaptor closure, because it is not a function object.
|
||||
struct NotCallable : ranges::range_adaptor_closure<NotCallable> {};
|
||||
static_assert(!is_range_adaptor_closure<NotCallable>());
|
||||
|
||||
// Is not a range adaptor closure, because it does not accept a range as argument.
|
||||
struct NotCallableWithRange : ranges::range_adaptor_closure<NotCallableWithRange> {
|
||||
void operator()() {}
|
||||
};
|
||||
static_assert(!is_range_adaptor_closure<NotCallableWithRange>());
|
||||
|
||||
// Is not a range adaptor closure, because it doesn't derive from range_adaptor_closure.
|
||||
struct NotDerivedFrom {
|
||||
void operator()(const TestRange&) {}
|
||||
};
|
||||
static_assert(!is_range_adaptor_closure<NotDerivedFrom>());
|
||||
|
||||
// Is not a range adaptor closure, because it inherits privately from range_adaptor_closure.
|
||||
struct DerivedPrivately : private ranges::range_adaptor_closure<DerivedPrivately> {
|
||||
void operator()(const TestRange&) {}
|
||||
};
|
||||
static_assert(!is_range_adaptor_closure<DerivedPrivately>());
|
||||
|
||||
// Is not a range adaptor closure, because it inherits from the wrong specialization of range_adaptor_closure.
|
||||
struct DerivedFromWrongSpecialization : ranges::range_adaptor_closure<IdentityRangeAdaptorClosure> {
|
||||
void operator()(const TestRange&) {}
|
||||
};
|
||||
static_assert(!is_range_adaptor_closure<DerivedFromWrongSpecialization>());
|
||||
|
||||
// Is not a range adaptor closure, because it has two base classes which are specializations of
|
||||
// range_adaptor_closure.
|
||||
struct DerivedFromTwoSpecializations : ranges::range_adaptor_closure<DerivedFromTwoSpecializations>,
|
||||
ranges::range_adaptor_closure<IdentityRangeAdaptorClosure> {
|
||||
void operator()(const TestRange&) {}
|
||||
};
|
||||
static_assert(!is_range_adaptor_closure<DerivedFromTwoSpecializations>());
|
||||
|
||||
// Is not a range adaptor closure, because it models ranges::range.
|
||||
struct ModelsRange : ranges::range_adaptor_closure<ModelsRange> {
|
||||
void operator()(const TestRange&) {}
|
||||
|
||||
int* begin() {
|
||||
return nullptr;
|
||||
}
|
||||
int* begin() const {
|
||||
return nullptr;
|
||||
}
|
||||
int* end() {
|
||||
return nullptr;
|
||||
}
|
||||
int* end() const {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
static_assert(ranges::range<ModelsRange>);
|
||||
static_assert(!is_range_adaptor_closure<ModelsRange>());
|
||||
|
||||
struct RangeAdaptorClosureMemberRefQualTest : ranges::range_adaptor_closure<RangeAdaptorClosureMemberRefQualTest> {
|
||||
constexpr ranges::empty_view<char> operator()(const auto&) & {
|
||||
return views::empty<char>;
|
||||
}
|
||||
|
||||
constexpr ranges::empty_view<short> operator()(const auto&) && {
|
||||
return views::empty<short>;
|
||||
}
|
||||
|
||||
constexpr ranges::empty_view<float> operator()(const auto&) const& {
|
||||
return views::empty<float>;
|
||||
}
|
||||
|
||||
constexpr ranges::empty_view<double> operator()(const auto&) const&& {
|
||||
return views::empty<double>;
|
||||
}
|
||||
};
|
||||
static_assert(CanPipe_R<TestRange, RangeAdaptorClosureMemberRefQualTest&, ranges::empty_view<char>>);
|
||||
static_assert(CanPipe_R<TestRange, RangeAdaptorClosureMemberRefQualTest&&, ranges::empty_view<short>>);
|
||||
static_assert(CanPipe_R<TestRange, RangeAdaptorClosureMemberRefQualTest const&, ranges::empty_view<float>>);
|
||||
static_assert(CanPipe_R<TestRange, RangeAdaptorClosureMemberRefQualTest const&&, ranges::empty_view<double>>);
|
||||
|
||||
using FirstIdentityThenMemberRefQualTest = decltype(
|
||||
IdentityRangeAdaptorClosure{} | RangeAdaptorClosureMemberRefQualTest{});
|
||||
static_assert(CanPipe_R<TestRange, FirstIdentityThenMemberRefQualTest&, ranges::empty_view<char>>);
|
||||
static_assert(CanPipe_R<TestRange, FirstIdentityThenMemberRefQualTest&&, ranges::empty_view<short>>);
|
||||
static_assert(CanPipe_R<TestRange, FirstIdentityThenMemberRefQualTest const&, ranges::empty_view<float>>);
|
||||
static_assert(CanPipe_R<TestRange, FirstIdentityThenMemberRefQualTest const&&, ranges::empty_view<double>>);
|
||||
|
||||
using FirstTransformThenMemberRefQualTest = decltype(
|
||||
views::transform([](auto x) { return x; }) | RangeAdaptorClosureMemberRefQualTest{});
|
||||
static_assert(CanPipe_R<TestRange, FirstTransformThenMemberRefQualTest&, ranges::empty_view<char>>);
|
||||
static_assert(CanPipe_R<TestRange, FirstTransformThenMemberRefQualTest&&, ranges::empty_view<short>>);
|
||||
static_assert(CanPipe_R<TestRange, FirstTransformThenMemberRefQualTest const&, ranges::empty_view<float>>);
|
||||
static_assert(CanPipe_R<TestRange, FirstTransformThenMemberRefQualTest const&&, ranges::empty_view<double>>);
|
||||
|
||||
using FirstMemberRefQualTestThenAll = decltype(RangeAdaptorClosureMemberRefQualTest{} | views::all);
|
||||
static_assert(CanPipe_R<TestRange, FirstMemberRefQualTestThenAll&, ranges::empty_view<char>>);
|
||||
static_assert(CanPipe_R<TestRange, FirstMemberRefQualTestThenAll&&, ranges::empty_view<short>>);
|
||||
static_assert(CanPipe_R<TestRange, FirstMemberRefQualTestThenAll const&, ranges::empty_view<float>>);
|
||||
static_assert(CanPipe_R<TestRange, FirstMemberRefQualTestThenAll const&&, ranges::empty_view<double>>);
|
||||
|
||||
struct RangeAdaptorClosureParameterRefQualTest
|
||||
: ranges::range_adaptor_closure<RangeAdaptorClosureParameterRefQualTest> {
|
||||
constexpr char operator()(TestRange&) {
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr short operator()(TestRange&&) {
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr float operator()(const TestRange&) {
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr double operator()(const TestRange&&) {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
static_assert(CanPipe_R<TestRange&, RangeAdaptorClosureParameterRefQualTest, char>);
|
||||
static_assert(CanPipe_R<TestRange&&, RangeAdaptorClosureParameterRefQualTest, short>);
|
||||
static_assert(CanPipe_R<const TestRange&, RangeAdaptorClosureParameterRefQualTest, float>);
|
||||
static_assert(CanPipe_R<const TestRange&&, RangeAdaptorClosureParameterRefQualTest, double>);
|
||||
|
||||
struct MoveOnlyRangeAdaptorClosure : ranges::range_adaptor_closure<MoveOnlyRangeAdaptorClosure> {
|
||||
MoveOnlyRangeAdaptorClosure() = default;
|
||||
MoveOnlyRangeAdaptorClosure(const MoveOnlyRangeAdaptorClosure&) = delete;
|
||||
MoveOnlyRangeAdaptorClosure(MoveOnlyRangeAdaptorClosure&&) = default;
|
||||
|
||||
void operator()(const TestRange&) {}
|
||||
};
|
||||
static_assert(CanPipe<TestRange, MoveOnlyRangeAdaptorClosure>);
|
||||
static_assert(CanPipe<TestRange, MoveOnlyRangeAdaptorClosure&>);
|
||||
static_assert(CanPipe<MoveOnlyRangeAdaptorClosure, IdentityRangeAdaptorClosure>);
|
||||
static_assert(CanPipe<IdentityRangeAdaptorClosure, MoveOnlyRangeAdaptorClosure>);
|
||||
static_assert(!CanPipe<MoveOnlyRangeAdaptorClosure&, IdentityRangeAdaptorClosure>);
|
||||
static_assert(!CanPipe<IdentityRangeAdaptorClosure, MoveOnlyRangeAdaptorClosure&>);
|
||||
|
||||
class TimesTwoAdaptor : public ranges::range_adaptor_closure<TimesTwoAdaptor> {
|
||||
public:
|
||||
template <ranges::range R>
|
||||
constexpr auto operator()(R&& range) const {
|
||||
return forward<R>(range) | views::transform([](auto x) { return x * 2; });
|
||||
}
|
||||
};
|
||||
|
||||
class DividedByTwoAdaptor : public ranges::range_adaptor_closure<DividedByTwoAdaptor> {
|
||||
public:
|
||||
template <ranges::range R>
|
||||
constexpr auto operator()(R&& range) const {
|
||||
return forward<R>(range) | views::transform([](auto x) { return x / 2; });
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool test_user_defined_adaptors() {
|
||||
const array<int, 3> numbers{1, 2, 3};
|
||||
const array<int, 3> numbers_times_two{2, 4, 6};
|
||||
assert(ranges::equal(numbers_times_two, numbers | TimesTwoAdaptor{}));
|
||||
assert(ranges::equal(numbers, (numbers | TimesTwoAdaptor{}) | DividedByTwoAdaptor{}));
|
||||
assert(ranges::equal(numbers, numbers | (TimesTwoAdaptor{} | DividedByTwoAdaptor{})));
|
||||
assert(ranges::equal(numbers_times_two,
|
||||
(numbers | TimesTwoAdaptor{})
|
||||
| (TimesTwoAdaptor{} | TimesTwoAdaptor{} | DividedByTwoAdaptor{} | DividedByTwoAdaptor{})));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test_mixing_of_range_adaptors() {
|
||||
const array<int, 3> numbers{1, 2, 3};
|
||||
assert(ranges::equal(numbers, numbers | (TimesTwoAdaptor{} | views::transform([](int x) { return x / 2; }))));
|
||||
|
||||
const auto mixed_pipeline = TimesTwoAdaptor{} | views::reverse | DividedByTwoAdaptor{} | views::reverse;
|
||||
assert(ranges::equal(mixed_pipeline(numbers), numbers));
|
||||
assert(ranges::equal(numbers | mixed_pipeline, numbers));
|
||||
|
||||
auto factory_pipeline = views::iota(1) | TimesTwoAdaptor{} | views::take(3);
|
||||
assert(ranges::equal(factory_pipeline, array{2, 4, 6}));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert(test_user_defined_adaptors());
|
||||
static_assert(test_user_defined_adaptors());
|
||||
|
||||
assert(test_mixing_of_range_adaptors());
|
||||
static_assert(test_mixing_of_range_adaptors());
|
||||
}
|
|
@ -272,6 +272,20 @@ STATIC_ASSERT(__cpp_lib_barrier == 201907L);
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if _HAS_CXX23
|
||||
#ifndef __cpp_lib_bind_back
|
||||
#error __cpp_lib_bind_back is not defined
|
||||
#elif __cpp_lib_bind_back != 202202L
|
||||
#error __cpp_lib_bind_back is not 202202L
|
||||
#else
|
||||
STATIC_ASSERT(__cpp_lib_bind_back == 202202L);
|
||||
#endif
|
||||
#else
|
||||
#ifdef __cpp_lib_bind_back
|
||||
#error __cpp_lib_bind_back is defined
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if _HAS_CXX20
|
||||
#ifndef __cpp_lib_bind_front
|
||||
#error __cpp_lib_bind_front is not defined
|
||||
|
@ -1440,7 +1454,15 @@ STATIC_ASSERT(__cpp_lib_polymorphic_allocator == 201902L);
|
|||
STATIC_ASSERT(__cpp_lib_quoted_string_io == 201304L);
|
||||
#endif
|
||||
|
||||
#if _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
|
||||
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
|
||||
#ifndef __cpp_lib_ranges
|
||||
#error __cpp_lib_ranges is not defined
|
||||
#elif __cpp_lib_ranges != 202202L
|
||||
#error __cpp_lib_ranges is not 202202L
|
||||
#else
|
||||
STATIC_ASSERT(__cpp_lib_ranges == 202202L);
|
||||
#endif
|
||||
#elif _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
|
||||
#ifndef __cpp_lib_ranges
|
||||
#error __cpp_lib_ranges is not defined
|
||||
#elif __cpp_lib_ranges != 202110L
|
||||
|
|
Загрузка…
Ссылка в новой задаче