This simplifies the usage of `__less` by making the class not depend on the types compared, but instead the `operator()`. We can't remove the template completely because we explicitly instantiate `std::__sort` with `__less<T>`.
Reviewed By: ldionne, #libc
Spies: arichardson, EricWF, libcxx-commits, mgrang
Differential Revision: https://reviews.llvm.org/D145285
bool
binary_search(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value)
{
- return std::binary_search(__first, __last, __value,
- __less<typename iterator_traits<_ForwardIterator>::value_type, _Tp>());
+ return std::binary_search(__first, __last, __value, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
const _Tp&
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi)
{
- return _VSTD::clamp(__v, __lo, __hi, __less<_Tp>());
+ return _VSTD::clamp(__v, __lo, __hi, __less<>());
}
#endif
template <class _Lhs, class _Rhs>
struct __is_trivial_equality_predicate<__equal_to, _Lhs, _Rhs> : true_type {};
-template <class _T1, class _T2 = _T1>
-struct __less
-{
- _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
- bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
-
- _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
- bool operator()(const _T1& __x, const _T2& __y) const {return __x < __y;}
-
- _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
- bool operator()(const _T2& __x, const _T1& __y) const {return __x < __y;}
-
- _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
- bool operator()(const _T2& __x, const _T2& __y) const {return __x < __y;}
-};
-
-template <class _T1>
-struct __less<_T1, _T1>
-{
- _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
- bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
-};
-
-template <class _T1>
-struct __less<const _T1, _T1>
-{
- _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
- bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
-};
-
-template <class _T1>
-struct __less<_T1, const _T1>
-{
- _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
- bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
+// The definition is required because __less is part of the ABI, but it's empty
+// because all comparisons should be transparent.
+template <class _T1 = void, class _T2 = _T1>
+struct __less {};
+
+template <>
+struct __less<void, void> {
+ template <class _Tp, class _Up>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp& __lhs, const _Up& __rhs) const {
+ return __lhs < __rhs;
+ }
};
_LIBCPP_END_NAMESPACE_STD
template <class _ForwardIterator, class _Tp>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator, _ForwardIterator>
equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
- return std::equal_range(
- std::move(__first),
- std::move(__last),
- __value,
- __less<typename iterator_traits<_ForwardIterator>::value_type, _Tp>());
+ return std::equal_range(std::move(__first), std::move(__last), __value, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
template <class _InputIterator1, class _InputIterator2>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
includes(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) {
- return std::includes(
- std::move(__first1),
- std::move(__last1),
- std::move(__first2),
- std::move(__last2),
- __less<typename iterator_traits<_InputIterator1>::value_type,
- typename iterator_traits<_InputIterator2>::value_type>());
+ return std::includes(std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __less<>());
}
_LIBCPP_END_NAMESPACE_STD
void
inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last)
{
- std::inplace_merge(std::move(__first), std::move(__middle), std::move(__last),
- __less<typename iterator_traits<_BidirectionalIterator>::value_type>());
+ std::inplace_merge(std::move(__first), std::move(__middle), std::move(__last), __less<>());
}
_LIBCPP_END_NAMESPACE_STD
bool
is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
- return _VSTD::is_heap(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ return _VSTD::is_heap(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator
is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
- return _VSTD::__is_heap_until(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ return _VSTD::__is_heap_until(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
bool
is_sorted(_ForwardIterator __first, _ForwardIterator __last)
{
- return _VSTD::is_sorted(__first, __last, __less<typename iterator_traits<_ForwardIterator>::value_type>());
+ return _VSTD::is_sorted(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
is_sorted_until(_ForwardIterator __first, _ForwardIterator __last)
{
- return _VSTD::is_sorted_until(__first, __last, __less<typename iterator_traits<_ForwardIterator>::value_type>());
+ return _VSTD::is_sorted_until(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
lexicographical_compare(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2)
{
- return _VSTD::lexicographical_compare(__first1, __last1, __first2, __last2,
- __less<typename iterator_traits<_InputIterator1>::value_type,
- typename iterator_traits<_InputIterator2>::value_type>());
+ return _VSTD::lexicographical_compare(__first1, __last1, __first2, __last2, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
template <class _ForwardIterator, class _Tp>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
_ForwardIterator lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
- return std::lower_bound(__first, __last, __value,
- __less<typename iterator_traits<_ForwardIterator>::value_type, _Tp>());
+ return std::lower_bound(__first, __last, __value, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
template <class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) {
- std::make_heap(std::move(__first), std::move(__last),
- __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ std::make_heap(std::move(__first), std::move(__last), __less<>());
}
_LIBCPP_END_NAMESPACE_STD
const _Tp&
max(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b)
{
- return _VSTD::max(__a, __b, __less<_Tp>());
+ return _VSTD::max(__a, __b, __less<>());
}
#ifndef _LIBCPP_CXX03_LANG
_Tp
max(initializer_list<_Tp> __t)
{
- return *_VSTD::max_element(__t.begin(), __t.end(), __less<_Tp>());
+ return *_VSTD::max_element(__t.begin(), __t.end(), __less<>());
}
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator
max_element(_ForwardIterator __first, _ForwardIterator __last)
{
- return _VSTD::max_element(__first, __last,
- __less<typename iterator_traits<_ForwardIterator>::value_type>());
+ return _VSTD::max_element(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
merge(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result)
{
- typedef typename iterator_traits<_InputIterator1>::value_type __v1;
- typedef typename iterator_traits<_InputIterator2>::value_type __v2;
- return _VSTD::merge(__first1, __last1, __first2, __last2, __result, __less<__v1, __v2>());
+ return _VSTD::merge(__first1, __last1, __first2, __last2, __result, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
const _Tp&
min(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b)
{
- return _VSTD::min(__a, __b, __less<_Tp>());
+ return _VSTD::min(__a, __b, __less<>());
}
#ifndef _LIBCPP_CXX03_LANG
_Tp
min(initializer_list<_Tp> __t)
{
- return *_VSTD::min_element(__t.begin(), __t.end(), __less<_Tp>());
+ return *_VSTD::min_element(__t.begin(), __t.end(), __less<>());
}
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator
min_element(_ForwardIterator __first, _ForwardIterator __last)
{
- return _VSTD::min_element(__first, __last,
- __less<typename iterator_traits<_ForwardIterator>::value_type>());
+ return _VSTD::min_element(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
pair<const _Tp&, const _Tp&>
minmax(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b)
{
- return std::minmax(__a, __b, __less<_Tp>());
+ return std::minmax(__a, __b, __less<>());
}
#ifndef _LIBCPP_CXX03_LANG
pair<_Tp, _Tp>
minmax(initializer_list<_Tp> __t)
{
- return std::minmax(__t, __less<_Tp>());
+ return std::minmax(__t, __less<>());
}
#endif // _LIBCPP_CXX03_LANG
template <class _ForwardIterator>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
pair<_ForwardIterator, _ForwardIterator> minmax_element(_ForwardIterator __first, _ForwardIterator __last) {
- return std::minmax_element(__first, __last, __less<typename iterator_traits<_ForwardIterator>::value_type>());
+ return std::minmax_element(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
bool
next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last)
{
- return _VSTD::next_permutation(__first, __last,
- __less<typename iterator_traits<_BidirectionalIterator>::value_type>());
+ return _VSTD::next_permutation(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
template <class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last) {
- std::nth_element(std::move(__first), std::move(__nth), std::move(__last), __less<typename
- iterator_traits<_RandomAccessIterator>::value_type>());
+ std::nth_element(std::move(__first), std::move(__nth), std::move(__last), __less<>());
}
_LIBCPP_END_NAMESPACE_STD
void
partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last)
{
- _VSTD::partial_sort(__first, __middle, __last,
- __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ _VSTD::partial_sort(__first, __middle, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
partial_sort_copy(_InputIterator __first, _InputIterator __last,
_RandomAccessIterator __result_first, _RandomAccessIterator __result_last)
{
- return _VSTD::partial_sort_copy(__first, __last, __result_first, __result_last,
- __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ return _VSTD::partial_sort_copy(__first, __last, __result_first, __result_last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
template <class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) {
- std::pop_heap(std::move(__first), std::move(__last),
- __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ std::pop_heap(std::move(__first), std::move(__last), __less<>());
}
_LIBCPP_END_NAMESPACE_STD
bool
prev_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last)
{
- return _VSTD::prev_permutation(__first, __last,
- __less<typename iterator_traits<_BidirectionalIterator>::value_type>());
+ return _VSTD::prev_permutation(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
template <class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) {
- std::push_heap(std::move(__first), std::move(__last),
- __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ std::push_heap(std::move(__first), std::move(__last), __less<>());
}
_LIBCPP_END_NAMESPACE_STD
_InputIterator2 __first2,
_InputIterator2 __last2,
_OutputIterator __result) {
- return std::__set_difference<_ClassicAlgPolicy>(
- __first1,
- __last1,
- __first2,
- __last2,
- __result,
- __less<typename iterator_traits<_InputIterator1>::value_type,
- typename iterator_traits<_InputIterator2>::value_type>()).second;
+ return std::__set_difference<_ClassicAlgPolicy>(__first1, __last1, __first2, __last2, __result, __less<>()).second;
}
_LIBCPP_END_NAMESPACE_STD
std::move(__first2),
std::move(__last2),
std::move(__result),
- __less<typename iterator_traits<_InputIterator1>::value_type,
- typename iterator_traits<_InputIterator2>::value_type>())
+ __less<>())
.__out_;
}
std::move(__first2),
std::move(__last2),
std::move(__result),
- __less<typename iterator_traits<_InputIterator1>::value_type,
- typename iterator_traits<_InputIterator2>::value_type>());
+ __less<>());
}
_LIBCPP_END_NAMESPACE_STD
std::move(__first2),
std::move(__last2),
std::move(__result),
- __less<typename iterator_traits<_InputIterator1>::value_type,
- typename iterator_traits<_InputIterator2>::value_type>());
+ __less<>());
}
_LIBCPP_END_NAMESPACE_STD
// The comparator being simple is a prerequisite for using the branchless optimization.
template <class _Tp>
struct __is_simple_comparator : false_type {};
-template <class _Tp>
-struct __is_simple_comparator<__less<_Tp>&> : true_type {};
+template <>
+struct __is_simple_comparator<__less<>&> : true_type {};
template <class _Tp>
struct __is_simple_comparator<less<_Tp>&> : true_type {};
template <class _Tp>
long double>;
template <class _AlgPolicy, class _Type, __enable_if_t<__sort_is_specialized_in_library<_Type>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, __less<_Type>& __comp) {
+_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, __less<>&) {
+ __less<_Type> __comp;
std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp);
}
template <class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
- std::sort(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ std::sort(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
template <class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) {
- std::sort_heap(std::move(__first), std::move(__last),
- __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ std::sort_heap(std::move(__first), std::move(__last), __less<>());
}
_LIBCPP_END_NAMESPACE_STD
template <class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI
void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) {
- std::stable_sort(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+ std::stable_sort(__first, __last, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
template <class _ForwardIterator, class _Tp, class _Compare>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp) {
- static_assert(is_copy_constructible<_ForwardIterator>::value,
- "Iterator has to be copy constructible");
+ static_assert(is_copy_constructible<_ForwardIterator>::value, "Iterator has to be copy constructible");
return std::__upper_bound<_ClassicAlgPolicy>(
std::move(__first), std::move(__last), __value, std::move(__comp), std::__identity());
}
template <class _ForwardIterator, class _Tp>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
- return std::upper_bound(
- std::move(__first),
- std::move(__last),
- __value,
- __less<_Tp, typename iterator_traits<_ForwardIterator>::value_type>());
+ return std::upper_bound(std::move(__first), std::move(__last), __value, __less<>());
}
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_HIDE_FROM_ABI __remove_return_type unique(_BinaryPredicate __binary_pred);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
- void merge(forward_list&& __x) {merge(__x, __less<value_type>());}
+ void merge(forward_list&& __x) {merge(__x, __less<>());}
template <class _Compare>
_LIBCPP_INLINE_VISIBILITY
void merge(forward_list&& __x, _Compare __comp)
{merge(__x, _VSTD::move(__comp));}
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
- void merge(forward_list& __x) {merge(__x, __less<value_type>());}
+ void merge(forward_list& __x) {merge(__x, __less<>());}
template <class _Compare>
_LIBCPP_HIDE_FROM_ABI void merge(forward_list& __x, _Compare __comp);
_LIBCPP_INLINE_VISIBILITY
- void sort() {sort(__less<value_type>());}
+ void sort() {sort(__less<>());}
template <class _Compare> _LIBCPP_INLINE_VISIBILITY void sort(_Compare __comp);
_LIBCPP_HIDE_FROM_ABI void reverse() _NOEXCEPT;
void
list<_Tp, _Alloc>::merge(list& __c)
{
- merge(__c, __less<value_type>());
+ merge(__c, __less<>());
}
template <class _Tp, class _Alloc>
void
list<_Tp, _Alloc>::sort()
{
- sort(__less<value_type>());
+ sort(__less<>());
}
template <class _Tp, class _Alloc>
// that the default comparator is in use so that we are sure that there are no
// branches in the comparator.
std::__introsort<_ClassicAlgPolicy,
- Comp&,
+ ranges::less,
RandomAccessIterator,
- __use_branchless_sort<Comp, RandomAccessIterator>::value>(first, last, comp, depth_limit);
+ __use_branchless_sort<ranges::less, RandomAccessIterator>::value>(
+ first, last, ranges::less{}, depth_limit);
}
// clang-format off
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+
+#include "test_macros.h"
+
+template <class T>
+struct Iterator {
+ using value_type = T;
+ using pointer = value_type*;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category = std::forward_iterator_tag;
+ struct reference {
+ T* ptr_;
+
+ reference(T* ptr) : ptr_(ptr) {}
+
+ friend bool operator<(reference a, reference b) { return *a.ptr_ < *b.ptr_; }
+ friend bool operator<(reference a, value_type const& b) { return *a.ptr_ < b; }
+ friend bool operator<(value_type const& a, reference b) { return a < *b.ptr_; }
+
+ operator T&() const;
+ };
+
+ Iterator& operator++() {
+ ptr_++;
+ return *this;
+ }
+
+ Iterator operator++(int) {
+ Iterator tmp = *this;
+ ptr_++;
+ return tmp;
+ }
+
+ friend bool operator==(Iterator const& a, Iterator const& b) { return a.ptr_ == b.ptr_; }
+ friend bool operator!=(Iterator const& a, Iterator const& b) { return !(a == b); }
+
+ reference operator*() const { return reference(ptr_); }
+
+ explicit Iterator(T* ptr) : ptr_(ptr) {}
+ Iterator() = default;
+ Iterator(Iterator const&) = default;
+ Iterator(Iterator&&) = default;
+
+ Iterator& operator=(Iterator const&) = default;
+ Iterator& operator=(Iterator&&) = default;
+
+private:
+ T* ptr_;
+};
+
+int main() {
+ int array[5] = {1, 2, 3, 4, 5};
+ Iterator<int> first(array);
+ Iterator<int> middle(array + 3);
+ Iterator<int> last(array + 5);
+ (void)std::binary_search(first, last, 3);
+ (void)std::equal_range(first, last, 3);
+ (void)std::includes(first, last, first, last);
+ (void)std::is_sorted_until(first, last);
+ (void)std::is_sorted(first, last);
+ (void)std::lexicographical_compare(first, last, first, last);
+ (void)std::lower_bound(first, last, 3);
+ (void)std::max_element(first, last);
+ (void)std::min_element(first, last);
+ (void)std::minmax_element(first, last);
+ (void)std::upper_bound(first, last, 3);
+}
template <int>
struct NoCompare {};
+#if TEST_STD_VER >= 14 && TEST_STD_VER <= 17
+// expected-error@*:* 3 {{no matching function for call to object of type 'std::__less<void, void>'}}
+#endif
+
int main(int, char**) {
{
typedef NoCompare<0> T;
libcxx/benchmarks/vector_operations.bench.cpp
libcxx/include/__algorithm/binary_search.h
libcxx/include/__algorithm/clamp.h
-libcxx/include/__algorithm/comp.h
libcxx/include/__algorithm/comp_ref_type.h
libcxx/include/__algorithm/copy_backward.h
libcxx/include/__algorithm/copy_if.h
libcxx/include/__algorithm/uniform_random_bit_generator_adaptor.h
libcxx/include/__algorithm/unwrap_iter.h
libcxx/include/__algorithm/unwrap_range.h
-libcxx/include/__algorithm/upper_bound.h
libcxx/include/any
libcxx/include/array
libcxx/include/__atomic/atomic_base.h