This implements P2248R8 + P3217R0, both approved for C++26.
The changes are mostly mechanical; the struggle is to keep readability
with the pre-P2248 signatures.
* For containers, "classic STL" algorithms and their parallel versions,
introduce a macro and amend their declarations/definitions with it.
The macro either expands to the defaulted parameter or to nothing
in pre-C++26 modes.
* For range algorithms, we need to reorder their template parameters.
I've done so unconditionally, because users cannot rely on template
parameters of algorithms (this is explicitly authorized by
[algorithms.requirements]/15). The defaults are then hidden behind
another macro.
libstdc++-v3/ChangeLog:
* include/bits/iterator_concepts.h: Add projected_value_t.
* include/bits/algorithmfwd.h: Add the default template
parameter to the relevant forward declarations.
* include/pstl/glue_algorithm_defs.h: Likewise.
* include/bits/ranges_algo.h: Add the default template
parameter to range-based algorithms.
* include/bits/ranges_algobase.h: Likewise.
* include/bits/ranges_util.h: Likewise.
* include/bits/ranges_base.h: Add helper macros.
* include/bits/stl_iterator_base_types.h: Add helper macro.
* include/bits/version.def: Add the new feature-testing macro.
* include/bits/version.h: Regenerate.
* include/std/algorithm: Pull the feature-testing macro.
* include/std/ranges: Likewise.
* include/std/deque: Pull the feature-testing macro, add
the default for std::erase.
* include/std/forward_list: Likewise.
* include/std/list: Likewise.
* include/std/string: Likewise.
* include/std/vector: Likewise.
* testsuite/23_containers/default_template_value.cc: New test.
* testsuite/25_algorithms/default_template_value.cc: New test.
Signed-off-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
any_of(_IIter, _IIter, _Predicate);
#endif
- template<typename _FIter, typename _Tp>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter)>
_GLIBCXX20_CONSTEXPR
bool
binary_search(_FIter, _FIter, const _Tp&);
- template<typename _FIter, typename _Tp, typename _Compare>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter),
+ typename _Compare>
_GLIBCXX20_CONSTEXPR
bool
binary_search(_FIter, _FIter, const _Tp&, _Compare);
// count
// count_if
- template<typename _FIter, typename _Tp>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter)>
_GLIBCXX20_CONSTEXPR
pair<_FIter, _FIter>
equal_range(_FIter, _FIter, const _Tp&);
- template<typename _FIter, typename _Tp, typename _Compare>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter),
+ typename _Compare>
_GLIBCXX20_CONSTEXPR
pair<_FIter, _FIter>
equal_range(_FIter, _FIter, const _Tp&, _Compare);
- template<typename _FIter, typename _Tp>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter)>
_GLIBCXX20_CONSTEXPR
void
fill(_FIter, _FIter, const _Tp&);
- template<typename _OIter, typename _Size, typename _Tp>
+ template<typename _OIter, typename _Size,
+ typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_OIter)>
_GLIBCXX20_CONSTEXPR
_OIter
fill_n(_OIter, _Size, const _Tp&);
void
iter_swap(_FIter1, _FIter2);
- template<typename _FIter, typename _Tp>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter)>
_GLIBCXX20_CONSTEXPR
_FIter
lower_bound(_FIter, _FIter, const _Tp&);
- template<typename _FIter, typename _Tp, typename _Compare>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter),
+ typename _Compare>
_GLIBCXX20_CONSTEXPR
_FIter
lower_bound(_FIter, _FIter, const _Tp&, _Compare);
// random_shuffle
- template<typename _FIter, typename _Tp>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter)>
_GLIBCXX20_CONSTEXPR
_FIter
remove(_FIter, _FIter, const _Tp&);
_FIter
remove_if(_FIter, _FIter, _Predicate);
- template<typename _IIter, typename _OIter, typename _Tp>
+ template<typename _IIter, typename _OIter,
+ typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_IIter)>
_GLIBCXX20_CONSTEXPR
_OIter
remove_copy(_IIter, _IIter, _OIter, const _Tp&);
_OIter
replace_copy(_IIter, _IIter, _OIter, const _Tp&, const _Tp&);
- template<typename _Iter, typename _OIter, typename _Predicate, typename _Tp>
+ template<typename _Iter, typename _OIter, typename _Predicate,
+ typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_OIter)>
_GLIBCXX20_CONSTEXPR
_OIter
replace_copy_if(_Iter, _Iter, _OIter, _Predicate, const _Tp&);
// unique_copy
- template<typename _FIter, typename _Tp>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter)>
_GLIBCXX20_CONSTEXPR
_FIter
upper_bound(_FIter, _FIter, const _Tp&);
- template<typename _FIter, typename _Tp, typename _Compare>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter),
+ typename _Compare>
_GLIBCXX20_CONSTEXPR
_FIter
upper_bound(_FIter, _FIter, const _Tp&, _Compare);
_FIter
adjacent_find(_FIter, _FIter, _BinaryPredicate);
- template<typename _IIter, typename _Tp>
+ template<typename _IIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_IIter)>
_GLIBCXX20_CONSTEXPR
typename iterator_traits<_IIter>::difference_type
count(_IIter, _IIter, const _Tp&);
bool
equal(_IIter1, _IIter1, _IIter2, _BinaryPredicate);
- template<typename _IIter, typename _Tp>
+ template<typename _IIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_IIter)>
_GLIBCXX20_CONSTEXPR
_IIter
find(_IIter, _IIter, const _Tp&);
#endif
#endif // HOSTED
- template<typename _FIter, typename _Tp>
+ template<typename _FIter, typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter)>
_GLIBCXX20_CONSTEXPR
void
replace(_FIter, _FIter, const _Tp&, const _Tp&);
- template<typename _FIter, typename _Predicate, typename _Tp>
+ template<typename _FIter, typename _Predicate,
+ typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter)>
_GLIBCXX20_CONSTEXPR
void
replace_if(_FIter, _FIter, _Predicate, const _Tp&);
_FIter1
search(_FIter1, _FIter1, _FIter2, _FIter2, _BinaryPredicate);
- template<typename _FIter, typename _Size, typename _Tp>
+ template<typename _FIter, typename _Size,
+ typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter)>
_GLIBCXX20_CONSTEXPR
_FIter
search_n(_FIter, _FIter, _Size, const _Tp&);
- template<typename _FIter, typename _Size, typename _Tp,
+ template<typename _FIter, typename _Size,
+ typename _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_FIter),
typename _BinaryPredicate>
_GLIBCXX20_CONSTEXPR
_FIter
using type = invoke_result_t<_Proj&, __indirect_value_t<_Iter>>;
};
+#if __glibcxx_algorithm_default_value_type // C++ >= 26
+ template<indirectly_readable _Iter,
+ indirectly_regular_unary_invocable<_Iter> _Proj>
+ using projected_value_t
+ = remove_cvref_t<invoke_result_t<_Proj&, iter_value_t<_Iter>&>>;
+#endif
+
// [alg.req], common algorithm requirements
/// [alg.req.ind.move], concept `indirectly_movable`
struct __count_fn
{
template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp, typename _Proj = identity>
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj)>
requires indirect_binary_predicate<ranges::equal_to,
projected<_Iter, _Proj>,
const _Tp*>
return __n;
}
- template<input_range _Range, typename _Tp, typename _Proj = identity>
+ template<input_range _Range, typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj)>
requires indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<_Range>, _Proj>,
const _Tp*>
struct __search_n_fn
{
- template<forward_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
- typename _Pred = ranges::equal_to, typename _Proj = identity>
+ template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+ typename _Pred = ranges::equal_to, typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj)>
requires indirectly_comparable<_Iter, const _Tp*, _Pred, _Proj>
constexpr subrange<_Iter>
operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __count,
}
}
- template<forward_range _Range, typename _Tp,
- typename _Pred = ranges::equal_to, typename _Proj = identity>
+ template<forward_range _Range,
+ typename _Pred = ranges::equal_to, typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj)>
requires indirectly_comparable<iterator_t<_Range>, const _Tp*,
_Pred, _Proj>
constexpr borrowed_subrange_t<_Range>
struct __replace_fn
{
template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp1, typename _Tp2, typename _Proj = identity>
+ typename _Proj = identity,
+ typename _Tp1 _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj),
+ typename _Tp2 _GLIBCXX26_DEF_VAL_T(_Tp1)>
requires indirectly_writable<_Iter, const _Tp2&>
&& indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>,
const _Tp1*>
return __first;
}
- template<input_range _Range,
- typename _Tp1, typename _Tp2, typename _Proj = identity>
+ template<input_range _Range, typename _Proj = identity,
+ typename _Tp1
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj),
+ typename _Tp2 _GLIBCXX26_DEF_VAL_T(_Tp1)>
requires indirectly_writable<iterator_t<_Range>, const _Tp2&>
&& indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<_Range>, _Proj>,
struct __replace_if_fn
{
template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp, typename _Proj = identity,
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj),
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
requires indirectly_writable<_Iter, const _Tp&>
constexpr _Iter
return std::move(__first);
}
- template<input_range _Range, typename _Tp, typename _Proj = identity,
+ template<input_range _Range, typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj),
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
_Pred>
requires indirectly_writable<iterator_t<_Range>, const _Tp&>
struct __replace_copy_fn
{
template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp1, typename _Tp2, output_iterator<const _Tp2&> _Out,
- typename _Proj = identity>
+ typename _Out, typename _Proj = identity,
+ typename _Tp1 _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj),
+ typename _Tp2 _GLIBCXX26_DEF_VAL_T(iter_value_t<_Out>)>
requires indirectly_copyable<_Iter, _Out>
&& indirect_binary_predicate<ranges::equal_to,
projected<_Iter, _Proj>, const _Tp1*>
+ && output_iterator<_Out, const _Tp2&>
constexpr replace_copy_result<_Iter, _Out>
operator()(_Iter __first, _Sent __last, _Out __result,
const _Tp1& __old_value, const _Tp2& __new_value,
return {std::move(__first), std::move(__result)};
}
- template<input_range _Range, typename _Tp1, typename _Tp2,
- output_iterator<const _Tp2&> _Out, typename _Proj = identity>
+ template<input_range _Range, typename _Out,
+ typename _Proj = identity,
+ typename _Tp1
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj),
+ typename _Tp2 _GLIBCXX26_DEF_VAL_T(iter_value_t<_Out>)>
requires indirectly_copyable<iterator_t<_Range>, _Out>
&& indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<_Range>, _Proj>,
const _Tp1*>
+ && output_iterator<_Out, const _Tp2&>
constexpr replace_copy_result<borrowed_iterator_t<_Range>, _Out>
operator()(_Range&& __r, _Out __result,
const _Tp1& __old_value, const _Tp2& __new_value,
struct __replace_copy_if_fn
{
template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp, output_iterator<const _Tp&> _Out,
+ typename _Out,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(iter_value_t<_Out>),
typename _Proj = identity,
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
requires indirectly_copyable<_Iter, _Out>
+ && output_iterator<_Out, const _Tp&>
constexpr replace_copy_if_result<_Iter, _Out>
operator()(_Iter __first, _Sent __last, _Out __result,
_Pred __pred, const _Tp& __new_value, _Proj __proj = {}) const
}
template<input_range _Range,
- typename _Tp, output_iterator<const _Tp&> _Out,
+ typename _Out,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(iter_value_t<_Out>),
typename _Proj = identity,
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
_Pred>
requires indirectly_copyable<iterator_t<_Range>, _Out>
+ && output_iterator<_Out, const _Tp&>
constexpr replace_copy_if_result<borrowed_iterator_t<_Range>, _Out>
operator()(_Range&& __r, _Out __result,
_Pred __pred, const _Tp& __new_value, _Proj __proj = {}) const
struct __remove_fn
{
template<permutable _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp, typename _Proj = identity>
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj)>
requires indirect_binary_predicate<ranges::equal_to,
projected<_Iter, _Proj>,
const _Tp*>
std::move(__pred), std::move(__proj));
}
- template<forward_range _Range, typename _Tp, typename _Proj = identity>
+ template<forward_range _Range, typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj)>
requires permutable<iterator_t<_Range>>
&& indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<_Range>, _Proj>,
struct __remove_copy_fn
{
template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
- weakly_incrementable _Out, typename _Tp, typename _Proj = identity>
+ weakly_incrementable _Out, typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj)>
requires indirectly_copyable<_Iter, _Out>
&& indirect_binary_predicate<ranges::equal_to,
projected<_Iter, _Proj>,
}
template<input_range _Range, weakly_incrementable _Out,
- typename _Tp, typename _Proj = identity>
+ typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj)>
requires indirectly_copyable<iterator_t<_Range>, _Out>
&& indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<_Range>, _Proj>,
struct __lower_bound_fn
{
template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp, typename _Proj = identity,
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj),
indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
_Comp = ranges::less>
constexpr _Iter
return __first;
}
- template<forward_range _Range, typename _Tp, typename _Proj = identity,
+ template<forward_range _Range,
+ typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj),
indirect_strict_weak_order<const _Tp*,
projected<iterator_t<_Range>, _Proj>>
_Comp = ranges::less>
struct __upper_bound_fn
{
template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp, typename _Proj = identity,
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj),
indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
_Comp = ranges::less>
constexpr _Iter
return __first;
}
- template<forward_range _Range, typename _Tp, typename _Proj = identity,
+ template<forward_range _Range,
+ typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj),
indirect_strict_weak_order<const _Tp*,
projected<iterator_t<_Range>, _Proj>>
_Comp = ranges::less>
struct __equal_range_fn
{
template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp, typename _Proj = identity,
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj),
indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
_Comp = ranges::less>
constexpr subrange<_Iter>
}
template<forward_range _Range,
- typename _Tp, typename _Proj = identity,
+ typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj),
indirect_strict_weak_order<const _Tp*,
projected<iterator_t<_Range>, _Proj>>
_Comp = ranges::less>
struct __binary_search_fn
{
template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp, typename _Proj = identity,
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj),
indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
_Comp = ranges::less>
constexpr bool
}
template<forward_range _Range,
- typename _Tp, typename _Proj = identity,
+ typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj),
indirect_strict_weak_order<const _Tp*,
projected<iterator_t<_Range>, _Proj>>
_Comp = ranges::less>
struct __contains_fn
{
template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
- typename _Tp, typename _Proj = identity>
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj)>
requires indirect_binary_predicate<ranges::equal_to,
projected<_Iter, _Proj>, const _Tp*>
constexpr bool
operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) const
{ return ranges::find(std::move(__first), __last, __value, std::move(__proj)) != __last; }
- template<input_range _Range, typename _Tp, typename _Proj = identity>
+ template<input_range _Range,
+ typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj)>
requires indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<_Range>, _Proj>, const _Tp*>
constexpr bool
struct __find_last_fn
{
- template<forward_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp, typename _Proj = identity>
+ template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj)>
requires indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>, const _Tp*>
constexpr subrange<_Iter>
operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) const
}
}
- template<forward_range _Range, typename _Tp, typename _Proj = identity>
+ template<forward_range _Range, typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj)>
requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Tp*>
constexpr borrowed_subrange_t<_Range>
operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const
return _Ret{std::move(__first), std::move(__accum)};
}
- template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
+ template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(iter_value_t<_Iter>),
__detail::__indirectly_binary_left_foldable<_Tp, _Iter> _Fp>
constexpr auto
operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
std::move(__init), std::move(__f));
}
- template<input_range _Range, typename _Tp,
+ template<input_range _Range,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(range_value_t<_Range>),
__detail::__indirectly_binary_left_foldable<_Tp, iterator_t<_Range>> _Fp>
constexpr auto
operator()(_Range&& __r, _Tp __init, _Fp __f) const
struct __fold_left_fn
{
- template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
+ template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(iter_value_t<_Iter>),
__detail::__indirectly_binary_left_foldable<_Tp, _Iter> _Fp>
constexpr auto
operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
std::move(__init), std::move(__f)).value;
}
- template<input_range _Range, typename _Tp,
+ template<input_range _Range,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(range_value_t<_Range>),
__detail::__indirectly_binary_left_foldable<_Tp, iterator_t<_Range>> _Fp>
constexpr auto
operator()(_Range&& __r, _Tp __init, _Fp __f) const
struct __fold_right_fn
{
- template<bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
+ template<bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(iter_value_t<_Iter>),
__detail::__indirectly_binary_right_foldable<_Tp, _Iter> _Fp>
constexpr auto
operator()(_Iter __first, _Sent __last, _Tp __init, _Fp __f) const
return __accum;
}
- template<bidirectional_range _Range, typename _Tp,
+ template<bidirectional_range _Range,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(range_value_t<_Range>),
__detail::__indirectly_binary_right_foldable<_Tp, iterator_t<_Range>> _Fp>
constexpr auto
operator()(_Range&& __r, _Tp __init, _Fp __f) const
struct __fill_n_fn
{
- template<typename _Tp, output_iterator<const _Tp&> _Out>
+ template<typename _Out,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(iter_value_t<_Out>)>
+ requires output_iterator<_Out, const _Tp&>
constexpr _Out
operator()(_Out __first, iter_difference_t<_Out> __n,
const _Tp& __value) const
struct __fill_fn
{
- template<typename _Tp,
- output_iterator<const _Tp&> _Out, sentinel_for<_Out> _Sent>
+ template<typename _Out,
+ sentinel_for<_Out> _Sent,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(iter_value_t<_Out>)>
+ requires output_iterator<_Out, const _Tp&>
constexpr _Out
operator()(_Out __first, _Sent __last, const _Tp& __value) const
{
}
}
- template<typename _Tp, output_range<const _Tp&> _Range>
+ template<typename _Range,
+ typename _Tp _GLIBCXX26_DEF_VAL_T(range_value_t<_Range>)>
+ requires output_range<_Range, const _Tp&>
constexpr borrowed_iterator_t<_Range>
operator()(_Range&& __r, const _Tp& __value) const
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" // __int128
+#if __glibcxx_algorithm_default_value_type // C++ >= 26
+# define _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_I, _P) = projected_value_t<_I, _P>
+#else
+# define _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_I, _P)
+#endif
+
#ifdef __cpp_lib_concepts
namespace std _GLIBCXX_VISIBILITY(default)
{
{
struct __find_fn
{
- template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
- typename _Proj = identity>
+ template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+ typename _Proj = identity,
+ typename _Tp _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(_Iter, _Proj)>
requires indirect_binary_predicate<ranges::equal_to,
projected<_Iter, _Proj>, const _Tp*>
constexpr _Iter
return __first;
}
- template<input_range _Range, typename _Tp, typename _Proj = identity>
+ template<input_range _Range, typename _Proj = identity,
+ typename _Tp
+ _GLIBCXX26_RANGE_ALGO_DEF_VAL_T(iterator_t<_Range>, _Proj)>
requires indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<_Range>, _Proj>,
const _Tp*>
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
+#if __glibcxx_algorithm_default_value_type // C++ >= 26
+# define _GLIBCXX26_DEF_VAL_T(T) = T
+# define _GLIBCXX26_ALGO_DEF_VAL_T(_Iterator) \
+ = typename iterator_traits<_Iterator>::value_type
+#else
+# define _GLIBCXX26_DEF_VAL_T(T)
+# define _GLIBCXX26_ALGO_DEF_VAL_T(_Iterator)
+#endif
+
#endif /* _STL_ITERATOR_BASE_TYPES_H */
};
};
+ftms = {
+ name = algorithm_default_value_type;
+ values = {
+ v = 202403;
+ cxxmin = 26;
+ };
+};
+
ftms = {
name = fstream_native_handle;
values = {
#endif /* !defined(__cpp_lib_unreachable) && defined(__glibcxx_want_unreachable) */
#undef __glibcxx_want_unreachable
+#if !defined(__cpp_lib_algorithm_default_value_type)
+# if (__cplusplus > 202302L)
+# define __glibcxx_algorithm_default_value_type 202403L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_algorithm_default_value_type)
+# define __cpp_lib_algorithm_default_value_type 202403L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_algorithm_default_value_type) && defined(__glibcxx_want_algorithm_default_value_type) */
+#undef __glibcxx_want_algorithm_default_value_type
+
#if !defined(__cpp_lib_fstream_native_handle)
# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
# define __glibcxx_fstream_native_handle 202306L
#ifndef _PSTL_GLUE_ALGORITHM_DEFS_H
#define _PSTL_GLUE_ALGORITHM_DEFS_H
+#include <bits/stl_iterator_base_types.h>
#include <bits/stl_pair.h>
#include "execution_defs.h"
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
find_if_not(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred);
-template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
find(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
// [alg.count]
-template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy,
typename iterator_traits<_ForwardIterator>::difference_type>
count(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
search(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
_ForwardIterator2 __s_last);
-template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp, class _BinaryPredicate>
+template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator), class _BinaryPredicate>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
search_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Size __count,
const _Tp& __value, _BinaryPredicate __pred);
-template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
search_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Size __count,
const _Tp& __value);
// [alg.replace]
-template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void>
replace_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred,
const _Tp& __new_value);
-template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void>
replace(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __old_value,
const _Tp& __new_value);
-template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _UnaryPredicate, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _UnaryPredicate, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator2)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
replace_copy_if(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _UnaryPredicate __pred, const _Tp& __new_value);
// [alg.fill]
-template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void>
fill(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
-template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
fill_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __count, const _Tp& __value);
remove_copy_if(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _Predicate __pred);
-template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator1)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
remove_copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result,
const _Tp& __value);
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
remove_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred);
-template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
+template <class _ExecutionPolicy, class _ForwardIterator, class _Tp _GLIBCXX26_ALGO_DEF_VAL_T(_ForwardIterator)>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
remove(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
# include <bits/ranges_algo.h>
#endif
+#define __glibcxx_want_algorithm_default_value_type
#define __glibcxx_want_clamp
#define __glibcxx_want_constexpr_algorithms
#define __glibcxx_want_freestanding_algorithm
#include <bits/range_access.h>
#include <bits/deque.tcc>
+#define __glibcxx_want_algorithm_default_value_type
#define __glibcxx_want_allocator_traits_is_always_equal
#define __glibcxx_want_erase_if
#define __glibcxx_want_nonmember_container_access
return 0;
}
- template<typename _Tp, typename _Alloc, typename _Up>
+ template<typename _Tp, typename _Alloc,
+ typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
inline typename deque<_Tp, _Alloc>::size_type
erase(deque<_Tp, _Alloc>& __cont, const _Up& __value)
{
# include <debug/forward_list>
#endif
+#define __glibcxx_want_algorithm_default_value_type
#define __glibcxx_want_allocator_traits_is_always_equal
#define __glibcxx_want_erase_if
#define __glibcxx_want_incomplete_container_elements
erase_if(forward_list<_Tp, _Alloc>& __cont, _Predicate __pred)
{ return __cont.remove_if(__pred); }
- template<typename _Tp, typename _Alloc, typename _Up>
+ template<typename _Tp, typename _Alloc,
+ typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
inline typename forward_list<_Tp, _Alloc>::size_type
erase(forward_list<_Tp, _Alloc>& __cont, const _Up& __value)
{
# include <debug/list>
#endif
+#define __glibcxx_want_algorithm_default_value_type
#define __glibcxx_want_allocator_traits_is_always_equal
#define __glibcxx_want_erase_if
#define __glibcxx_want_incomplete_container_elements
erase_if(list<_Tp, _Alloc>& __cont, _Predicate __pred)
{ return __cont.remove_if(__pred); }
- template<typename _Tp, typename _Alloc, typename _Up>
+ template<typename _Tp, typename _Alloc,
+ typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
inline typename list<_Tp, _Alloc>::size_type
erase(list<_Tp, _Alloc>& __cont, const _Up& __value)
{
#include <bits/ranges_util.h>
#include <bits/refwrap.h>
+#define __glibcxx_want_algorithm_default_value_type
#define __glibcxx_want_ranges
#define __glibcxx_want_ranges_as_const
#define __glibcxx_want_ranges_as_rvalue
#include <bits/basic_string.h>
#include <bits/basic_string.tcc>
+#define __glibcxx_want_algorithm_default_value_type
#define __glibcxx_want_allocator_traits_is_always_equal
#define __glibcxx_want_constexpr_char_traits
#define __glibcxx_want_constexpr_string
return __osz - __cont.size();
}
- template<typename _CharT, typename _Traits, typename _Alloc, typename _Up>
+ template<typename _CharT, typename _Traits, typename _Alloc,
+ typename _Up _GLIBCXX26_DEF_VAL_T(_CharT)>
_GLIBCXX20_CONSTEXPR
inline typename basic_string<_CharT, _Traits, _Alloc>::size_type
erase(basic_string<_CharT, _Traits, _Alloc>& __cont, const _Up& __value)
# include <debug/vector>
#endif
+#define __glibcxx_want_algorithm_default_value_type
#define __glibcxx_want_allocator_traits_is_always_equal
#define __glibcxx_want_constexpr_vector
#define __glibcxx_want_erase_if
return 0;
}
- template<typename _Tp, typename _Alloc, typename _Up>
+ template<typename _Tp, typename _Alloc,
+ typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
_GLIBCXX20_CONSTEXPR
inline typename vector<_Tp, _Alloc>::size_type
erase(vector<_Tp, _Alloc>& __cont, const _Up& __value)
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <string>
+#include <vector>
+
+#if !defined(__cpp_lib_algorithm_default_value_type)
+#error "Feature test macro for default template type for algorithms' values is missing"
+#elif __cpp_lib_algorithm_default_value_type < 202403L
+#error "Feature test macro for default template type for algorithms' values is wrong"
+#endif
+
+struct S {
+ S(int, double);
+ friend auto operator<=>(const S&, const S&) = default;
+};
+
+template<template<typename...> typename Container>
+void test_erase()
+{
+ Container<S> c;
+ std::erase(c, {1, 3.14});
+}
+
+void
+test()
+{
+ test_erase<std::deque>();
+ test_erase<std::forward_list>();
+ test_erase<std::list>();
+ test_erase<std::vector>();
+
+ std::string s;
+ std::erase(s, {'x'});
+
+ std::wstring ws;
+ std::erase(ws, {L'x'});
+}
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+
+#if !defined(__cpp_lib_algorithm_default_value_type)
+#error "Feature test macro for default template type for algorithms' values is missing"
+#elif __cpp_lib_algorithm_default_value_type < 202403L
+#error "Feature test macro for default template type for algorithms' values is wrong"
+#endif
+
+#include <execution>
+#include <ranges>
+#include <iterator>
+#include <vector>
+
+// Conversions from Input to Output will be used in certain algorithms.
+// Make Output have a different number of arguments to its constructor
+// so we can check whether a braced-init-list is indeed matching Input
+// or Output
+struct Output
+{
+ Output(char, float, long);
+};
+
+#define OUTPUT_VAL {'x', 1.171f, 10L}
+
+struct Input
+{
+ Input(int, double);
+ friend bool operator<=>(const Input &, const Input &) = default;
+ friend Input operator+(const Input &, const Input &);
+ operator Output() const;
+};
+
+#define INPUT_VAL {1, 3.14}
+
+void
+test()
+{
+ extern std::vector<Input> in;
+ extern std::vector<Output> out;
+
+ const auto pred = [](auto &&) { return true; };
+
+ // [alg.find]
+ (void) std::find(in.begin(), in.end(), INPUT_VAL);
+ (void) std::find(std::execution::seq, in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::find(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::find(in, INPUT_VAL);
+
+ // [alg.count]
+ (void) std::count(in.begin(), in.end(), INPUT_VAL);
+ (void) std::count(std::execution::seq, in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::count(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::count(in, INPUT_VAL);
+
+ // [alg.search]
+ (void) std::search_n(in.begin(), in.end(), 10, INPUT_VAL);
+ (void) std::search_n(in.begin(), in.end(), 10, INPUT_VAL, std::equal_to{});
+ (void) std::search_n(std::execution::seq, in.begin(), in.end(), 10, INPUT_VAL);
+ (void) std::search_n(std::execution::seq, in.begin(), in.end(), 10, INPUT_VAL, std::equal_to{});
+ (void) std::ranges::search_n(in.begin(), in.end(), 10, INPUT_VAL);
+ (void) std::ranges::search_n(in, 10, INPUT_VAL);
+
+ // [alg.replace]
+ (void) std::replace(in.begin(), in.end(), INPUT_VAL, INPUT_VAL);
+ (void) std::replace(std::execution::seq, in.begin(), in.end(), INPUT_VAL, INPUT_VAL);
+ (void) std::replace_if(in.begin(), in.end(), pred, INPUT_VAL);
+ (void) std::replace_if(std::execution::seq, in.begin(), in.end(), pred, INPUT_VAL);
+
+ (void) std::ranges::replace(in.begin(), in.end(), INPUT_VAL, INPUT_VAL);
+ (void) std::ranges::replace(in, INPUT_VAL, INPUT_VAL);
+ (void) std::ranges::replace_if(in.begin(), in.end(), pred, INPUT_VAL);
+ (void) std::ranges::replace_if(in, pred, INPUT_VAL);
+
+ (void) std::replace_copy_if(in.begin(), in.end(), out.begin(), pred, OUTPUT_VAL);
+ (void) std::replace_copy_if(std::execution::seq, in.begin(), in.end(), out.begin(), pred, OUTPUT_VAL);
+ (void) std::ranges::replace_copy_if(in.begin(), in.end(), out.begin(), pred, OUTPUT_VAL);
+ (void) std::ranges::replace_copy_if(in, out.begin(), pred, OUTPUT_VAL);
+
+ // Non-range replace_copy is deliberately skipped by P2248
+ (void) std::ranges::replace_copy(in.begin(), in.end(), out.begin(), INPUT_VAL, OUTPUT_VAL);
+ (void) std::ranges::replace_copy(in, out.begin(), INPUT_VAL, OUTPUT_VAL);
+
+ // [alg.fill]
+ (void) std::fill(in.begin(), in.end(), INPUT_VAL);
+ (void) std::fill(std::execution::seq, in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::fill(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::fill(in, INPUT_VAL);
+
+ (void) std::fill_n(in.begin(), 10, INPUT_VAL);
+ (void) std::fill_n(std::execution::seq, in.begin(), 10, INPUT_VAL);
+ (void) std::ranges::fill_n(in.begin(), 10, INPUT_VAL);
+
+ // [alg.remove]
+ (void) std::remove(in.begin(), in.end(), INPUT_VAL);
+ (void) std::remove(std::execution::seq, in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::remove(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::remove(in, INPUT_VAL);
+
+ (void) std::remove_copy(in.begin(), in.end(), out.begin(), INPUT_VAL);
+ (void) std::remove_copy(std::execution::seq, in.begin(), in.end(), out.begin(), INPUT_VAL);
+ (void) std::ranges::remove_copy(in.begin(), in.end(), out.begin(), INPUT_VAL);
+ (void) std::ranges::remove_copy(in, out.begin(), INPUT_VAL);
+
+ // [alg.binary.search]
+ (void) std::lower_bound(in.begin(), in.end(), INPUT_VAL);
+ (void) std::lower_bound(in.begin(), in.end(), INPUT_VAL, std::less{});
+ (void) std::ranges::lower_bound(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::lower_bound(in, INPUT_VAL);
+
+ (void) std::upper_bound(in.begin(), in.end(), INPUT_VAL);
+ (void) std::upper_bound(in.begin(), in.end(), INPUT_VAL, std::less{});
+ (void) std::ranges::upper_bound(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::upper_bound(in, INPUT_VAL);
+
+ (void) std::equal_range(in.begin(), in.end(), INPUT_VAL);
+ (void) std::equal_range(in.begin(), in.end(), INPUT_VAL, std::less{});
+ (void) std::ranges::equal_range(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::equal_range(in, INPUT_VAL);
+
+ (void) std::binary_search(in.begin(), in.end(), INPUT_VAL);
+ (void) std::binary_search(in.begin(), in.end(), INPUT_VAL, std::less{});
+ (void) std::ranges::binary_search(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::binary_search(in, INPUT_VAL);
+
+ // [alg.fold]
+ (void) std::ranges::fold_left(in.begin(), in.end(), INPUT_VAL, std::plus<>{});
+ (void) std::ranges::fold_left(in, INPUT_VAL, std::plus<>{});
+ (void) std::ranges::fold_right(in.begin(), in.end(), INPUT_VAL, std::plus<>{});
+ (void) std::ranges::fold_right(in, INPUT_VAL, std::plus<>{});
+ (void) std::ranges::fold_left_with_iter(in.begin(), in.end(), INPUT_VAL, std::plus<>{});
+ (void) std::ranges::fold_left_with_iter(in, INPUT_VAL, std::plus<>{});
+
+ // [alg.contains]
+ (void) std::ranges::contains(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::contains(in, INPUT_VAL);
+
+ // [alg.find.last]
+ (void) std::ranges::find_last(in.begin(), in.end(), INPUT_VAL);
+ (void) std::ranges::find_last(in, INPUT_VAL);
+}