mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-22 21:31:19 +08:00
libstdc++: Add remaining C++20 changes to iterator adaptors
This adds the missing parts of P0896R4 to reverse_iterator and move_iterator, so that they meet the C++20 requirements. This should be the last piece of P0896R4, meaning ranges support is now complete. The PR 94354 bug with reverse_iterator's comparisons is fixed for C++20 only, but that change should be extended to C++11, C++14 and C++17 modes in stage 1. * include/bits/stl_iterator.h (reverse_iterator::iterator_concept) (reverse_iterator::iterator_category): Define for C++20. (reverse_iterator): Define comparison operators correctly for C++20. (__normal_iterator): Add constraints to comparison operators for C++20. (move_iterator::operator++(int)) [__cpp_lib_concepts]: Define new overload for input iterators. (move_iterator): Add constraints to comparison operators for C++20. Define operator<=> for C++20. * testsuite/24_iterators/move_iterator/input_iterator.cc: New test. * testsuite/24_iterators/move_iterator/move_only.cc: New test. * testsuite/24_iterators/move_iterator/rel_ops_c++20.cc: New test. * testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc: New test.
This commit is contained in:
parent
ae6076b5bc
commit
81a8d137c2
@ -1,5 +1,18 @@
|
||||
2020-03-27 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
* include/bits/stl_iterator.h (reverse_iterator::iterator_concept)
|
||||
(reverse_iterator::iterator_category): Define for C++20.
|
||||
(reverse_iterator): Define comparison operators correctly for C++20.
|
||||
(__normal_iterator): Add constraints to comparison operators for C++20.
|
||||
(move_iterator::operator++(int)) [__cpp_lib_concepts]: Define new
|
||||
overload for input iterators.
|
||||
(move_iterator): Add constraints to comparison operators for C++20.
|
||||
Define operator<=> for C++20.
|
||||
* testsuite/24_iterators/move_iterator/input_iterator.cc: New test.
|
||||
* testsuite/24_iterators/move_iterator/move_only.cc: New test.
|
||||
* testsuite/24_iterators/move_iterator/rel_ops_c++20.cc: New test.
|
||||
* testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc: New test.
|
||||
|
||||
* include/bits/iterator_concepts.h (__detail::__decay_copy)
|
||||
(__detail::__member_begin, __detail::__adl_begin): Move here from
|
||||
<bits/range_access.h>.
|
||||
|
@ -88,6 +88,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if __cplusplus > 201703L && __cpp_lib_concepts
|
||||
namespace __detail
|
||||
{
|
||||
// Weaken iterator_category _Cat to _Limit if it is derived from that,
|
||||
// otherwise use _Otherwise.
|
||||
template<typename _Cat, typename _Limit, typename _Otherwise = _Cat>
|
||||
using __clamp_iter_cat
|
||||
= conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 24.4.1 Reverse iterators
|
||||
/**
|
||||
* Bidirectional and random access iterators have corresponding reverse
|
||||
@ -126,6 +137,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
typedef typename __traits_type::pointer pointer;
|
||||
typedef typename __traits_type::reference reference;
|
||||
|
||||
#if __cplusplus > 201703L && __cpp_lib_concepts
|
||||
using iterator_concept
|
||||
= conditional_t<random_access_iterator<_Iterator>,
|
||||
random_access_iterator_tag,
|
||||
bidirectional_iterator_tag>;
|
||||
using iterator_category
|
||||
= __detail::__clamp_iter_cat<typename __traits_type::iterator_category,
|
||||
random_access_iterator_tag>;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The default constructor value-initializes member @p current.
|
||||
* If it is a pointer, that means it is zero-initialized.
|
||||
@ -320,16 +341,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
{ return __t.operator->(); }
|
||||
};
|
||||
|
||||
// Used in unevaluated expressions to test for implicit conversion to bool.
|
||||
namespace __detail { bool __convbool(bool); }
|
||||
|
||||
//@{
|
||||
/**
|
||||
* @param __x A %reverse_iterator.
|
||||
* @param __y A %reverse_iterator.
|
||||
* @return A simple bool.
|
||||
*
|
||||
* Reverse iterators forward many operations to their underlying base()
|
||||
* iterators. Others are implemented in terms of one another.
|
||||
* Reverse iterators forward comparisons to their underlying base()
|
||||
* iterators.
|
||||
*
|
||||
*/
|
||||
#if __cplusplus <= 201703L
|
||||
template<typename _Iterator>
|
||||
inline _GLIBCXX17_CONSTEXPR bool
|
||||
operator==(const reverse_iterator<_Iterator>& __x,
|
||||
@ -403,6 +428,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
operator>=(const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y)
|
||||
{ return !(__x < __y); }
|
||||
#else // C++20
|
||||
template<typename _IteratorL, typename _IteratorR>
|
||||
constexpr auto
|
||||
operator==(const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y)
|
||||
-> decltype(__detail::__convbool(__x.base() == __y.base()))
|
||||
{ return __x.base() == __y.base(); }
|
||||
|
||||
template<typename _IteratorL, typename _IteratorR>
|
||||
constexpr auto
|
||||
operator!=(const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y)
|
||||
-> decltype(__detail::__convbool(__x.base() != __y.base()))
|
||||
{ return __x.base() != __y.base(); }
|
||||
|
||||
template<typename _IteratorL, typename _IteratorR>
|
||||
constexpr auto
|
||||
operator<(const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y)
|
||||
-> decltype(__detail::__convbool(__x.base() < __y.base()))
|
||||
{ return __x.base() < __y.base(); }
|
||||
|
||||
template<typename _IteratorL, typename _IteratorR>
|
||||
constexpr auto
|
||||
operator>(const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y)
|
||||
-> decltype(__detail::__convbool(__x.base() > __y.base()))
|
||||
{ return __x.base() > __y.base(); }
|
||||
|
||||
template<typename _IteratorL, typename _IteratorR>
|
||||
constexpr auto
|
||||
operator<=(const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y)
|
||||
-> decltype(__detail::__convbool(__x.base() <= __y.base()))
|
||||
{ return __x.base() <= __y.base(); }
|
||||
|
||||
template<typename _IteratorL, typename _IteratorR>
|
||||
constexpr auto
|
||||
operator>=(const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y)
|
||||
-> decltype(__detail::__convbool(__x.base() >= __y.base()))
|
||||
{ return __x.base() >= __y.base(); }
|
||||
#endif // C++20
|
||||
//@}
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
@ -1000,8 +1068,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
// Random access iterator requirements
|
||||
template<typename _IteratorL, typename _IteratorR, typename _Container>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
#if __cplusplus > 201703L
|
||||
constexpr auto
|
||||
#else
|
||||
inline bool
|
||||
#endif
|
||||
operator<(const __normal_iterator<_IteratorL, _Container>& __lhs,
|
||||
const __normal_iterator<_IteratorR, _Container>& __rhs)
|
||||
_GLIBCXX_NOEXCEPT
|
||||
@ -1016,8 +1087,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
{ return __lhs.base() < __rhs.base(); }
|
||||
|
||||
template<typename _IteratorL, typename _IteratorR, typename _Container>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
#if __cplusplus > 201703L
|
||||
constexpr auto
|
||||
#else
|
||||
inline bool
|
||||
#endif
|
||||
operator>(const __normal_iterator<_IteratorL, _Container>& __lhs,
|
||||
const __normal_iterator<_IteratorR, _Container>& __rhs)
|
||||
_GLIBCXX_NOEXCEPT
|
||||
@ -1032,8 +1106,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
{ return __lhs.base() > __rhs.base(); }
|
||||
|
||||
template<typename _IteratorL, typename _IteratorR, typename _Container>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
#if __cplusplus > 201703L
|
||||
constexpr auto
|
||||
#else
|
||||
inline bool
|
||||
#endif
|
||||
operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs,
|
||||
const __normal_iterator<_IteratorR, _Container>& __rhs)
|
||||
_GLIBCXX_NOEXCEPT
|
||||
@ -1048,8 +1125,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
{ return __lhs.base() <= __rhs.base(); }
|
||||
|
||||
template<typename _IteratorL, typename _IteratorR, typename _Container>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
#if __cplusplus > 201703L
|
||||
constexpr auto
|
||||
#else
|
||||
inline bool
|
||||
#endif
|
||||
operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs,
|
||||
const __normal_iterator<_IteratorR, _Container>& __rhs)
|
||||
_GLIBCXX_NOEXCEPT
|
||||
@ -1157,15 +1237,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
private:
|
||||
_Sent _M_last;
|
||||
};
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
// Weaken iterator_category _Cat to _Limit if it is derived from that,
|
||||
// otherwise use _Otherwise.
|
||||
template<typename _Cat, typename _Limit, typename _Otherwise = _Cat>
|
||||
using __clamp_iter_cat
|
||||
= conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>;
|
||||
}
|
||||
#endif // C++20
|
||||
|
||||
// 24.4.3 Move iterators
|
||||
@ -1266,6 +1337,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
#if __cpp_lib_concepts
|
||||
constexpr void
|
||||
operator++(int) requires (!forward_iterator<_Iterator>)
|
||||
{ ++_M_current; }
|
||||
#endif
|
||||
|
||||
_GLIBCXX17_CONSTEXPR move_iterator&
|
||||
operator--()
|
||||
{
|
||||
@ -1343,6 +1420,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
inline _GLIBCXX17_CONSTEXPR bool
|
||||
operator==(const move_iterator<_IteratorL>& __x,
|
||||
const move_iterator<_IteratorR>& __y)
|
||||
#if __cplusplus > 201703L && __cpp_lib_concepts
|
||||
requires requires { __detail::__convbool(__x.base() == __y.base()); }
|
||||
#endif
|
||||
{ return __x.base() == __y.base(); }
|
||||
|
||||
template<typename _Iterator>
|
||||
@ -1351,6 +1431,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
const move_iterator<_Iterator>& __y)
|
||||
{ return __x.base() == __y.base(); }
|
||||
|
||||
#if __cpp_lib_three_way_comparison
|
||||
template<typename _IteratorL,
|
||||
three_way_comparable_with<_IteratorL> _IteratorR>
|
||||
constexpr compare_three_way_result_t<_IteratorL, _IteratorR>
|
||||
operator<=>(const move_iterator<_IteratorL>& __x,
|
||||
const move_iterator<_IteratorR>& __y)
|
||||
{ return __x.base() <=> __y.base(); }
|
||||
#else
|
||||
template<typename _IteratorL, typename _IteratorR>
|
||||
inline _GLIBCXX17_CONSTEXPR bool
|
||||
operator!=(const move_iterator<_IteratorL>& __x,
|
||||
@ -1362,11 +1450,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
operator!=(const move_iterator<_Iterator>& __x,
|
||||
const move_iterator<_Iterator>& __y)
|
||||
{ return !(__x == __y); }
|
||||
#endif
|
||||
|
||||
template<typename _IteratorL, typename _IteratorR>
|
||||
inline _GLIBCXX17_CONSTEXPR bool
|
||||
operator<(const move_iterator<_IteratorL>& __x,
|
||||
const move_iterator<_IteratorR>& __y)
|
||||
#if __cplusplus > 201703L && __cpp_lib_concepts
|
||||
requires requires { __detail::__convbool(__x.base() < __y.base()); }
|
||||
#endif
|
||||
{ return __x.base() < __y.base(); }
|
||||
|
||||
template<typename _Iterator>
|
||||
@ -1379,6 +1471,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
inline _GLIBCXX17_CONSTEXPR bool
|
||||
operator<=(const move_iterator<_IteratorL>& __x,
|
||||
const move_iterator<_IteratorR>& __y)
|
||||
#if __cplusplus > 201703L && __cpp_lib_concepts
|
||||
requires requires { __detail::__convbool(__y.base() < __x.base()); }
|
||||
#endif
|
||||
{ return !(__y < __x); }
|
||||
|
||||
template<typename _Iterator>
|
||||
@ -1391,6 +1486,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
inline _GLIBCXX17_CONSTEXPR bool
|
||||
operator>(const move_iterator<_IteratorL>& __x,
|
||||
const move_iterator<_IteratorR>& __y)
|
||||
#if __cplusplus > 201703L && __cpp_lib_concepts
|
||||
requires requires { __detail::__convbool(__y.base() < __x.base()); }
|
||||
#endif
|
||||
{ return __y < __x; }
|
||||
|
||||
template<typename _Iterator>
|
||||
@ -1403,6 +1501,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
inline _GLIBCXX17_CONSTEXPR bool
|
||||
operator>=(const move_iterator<_IteratorL>& __x,
|
||||
const move_iterator<_IteratorR>& __y)
|
||||
#if __cplusplus > 201703L && __cpp_lib_concepts
|
||||
requires requires { __detail::__convbool(__x.base() < __y.base()); }
|
||||
#endif
|
||||
{ return !(__x < __y); }
|
||||
|
||||
template<typename _Iterator>
|
||||
|
@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do run { target c++2a } }
|
||||
|
||||
#include <iterator>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_iterators.h>
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
int a[2] = { 1, 2 };
|
||||
__gnu_test::test_container<int, __gnu_test::input_iterator_wrapper> c(a);
|
||||
auto miter = std::make_move_iterator(c.begin());
|
||||
VERIFY( *miter == 1 );
|
||||
miter++;
|
||||
VERIFY( *miter == 2 );
|
||||
|
||||
static_assert( std::is_void_v<decltype(miter++)> );
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
// Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <iterator>
|
||||
|
||||
struct move_only_iterator
|
||||
{
|
||||
move_only_iterator() = default;
|
||||
move_only_iterator(move_only_iterator&&) = default;
|
||||
move_only_iterator& operator=(move_only_iterator&&) = default;
|
||||
|
||||
move_only_iterator& operator++();
|
||||
move_only_iterator operator++(int);
|
||||
int& operator*() const;
|
||||
|
||||
bool operator==(const move_only_iterator&) const;
|
||||
};
|
||||
|
||||
template<> struct std::iterator_traits<move_only_iterator>
|
||||
{
|
||||
using value_type = int;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
};
|
||||
|
||||
static_assert(std::input_iterator<move_only_iterator>);
|
||||
|
||||
template<typename T>
|
||||
concept has_member_base = requires (T t) { std::forward<T>(t).base(); };
|
||||
|
||||
static_assert( ! has_member_base<std::move_iterator<move_iterator>&> );
|
||||
static_assert( ! has_member_base<const std::move_iterator<move_iterator>&> );
|
||||
static_assert( has_member_base<std::move_iterator<move_iterator>> );
|
||||
static_assert( ! has_member_base<const std::move_iterator<move_iterator>> );
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
std::move_iterator<move_only_iterator> m1, m2;
|
||||
m1 = std::make_move_iterator(move_only_iterator{});
|
||||
m2 = std::move(m1);
|
||||
m1.swap(m2);
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
// Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <iterator>
|
||||
|
||||
template<int>
|
||||
struct Iter
|
||||
{
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = int;
|
||||
using pointer = int*;
|
||||
using reference = int&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
Iter();
|
||||
|
||||
Iter& operator++();
|
||||
Iter operator++(int);
|
||||
Iter& operator--();
|
||||
Iter operator--(int);
|
||||
int& operator*() const;
|
||||
int* operator->() const;
|
||||
|
||||
int& operator[](difference_type) const;
|
||||
|
||||
Iter& operator+=(difference_type);
|
||||
Iter& operator-=(difference_type);
|
||||
|
||||
template<int N> friend Iter operator+(Iter<N>, difference_type);
|
||||
template<int N> friend Iter operator+(difference_type, Iter<N>);
|
||||
template<int N> friend Iter operator-(Iter<N>, difference_type);
|
||||
template<int N> friend difference_type operator-(Iter<N>, Iter<N>);
|
||||
|
||||
// Define the full set of operators for same-type comparisons
|
||||
template<int N> friend bool operator==(Iter<N>, Iter<N>); // synthesizes !=
|
||||
template<int N> friend bool operator<(Iter<N>, Iter<N>);
|
||||
template<int N> friend bool operator>(Iter<N>, Iter<N>);
|
||||
template<int N> friend bool operator<=(Iter<N>, Iter<N>);
|
||||
template<int N> friend bool operator>=(Iter<N>, Iter<N>);
|
||||
};
|
||||
|
||||
|
||||
static_assert( std::random_access_iterator<Iter<0>> );
|
||||
|
||||
int operator==(Iter<0>, long*);
|
||||
void* operator< (Iter<1>, long*);
|
||||
bool& operator< (long*, Iter<2>);
|
||||
|
||||
using std::move_iterator;
|
||||
|
||||
static_assert( std::three_way_comparable<move_iterator<Iter<0>>> );
|
||||
|
||||
move_iterator<Iter<0>> l0{Iter<0>()};
|
||||
move_iterator<Iter<1>> l1{Iter<1>()};
|
||||
move_iterator<Iter<2>> l2{Iter<2>()};
|
||||
move_iterator<long*> r{nullptr};
|
||||
|
||||
bool b0 = l0 == r;
|
||||
bool b1 = l0 != r;
|
||||
bool b2 = l1 < r;
|
||||
bool b3 = l2 > r;
|
||||
bool b4 = l2 <= r;
|
||||
bool b5 = l1 >= r;
|
||||
|
||||
template<int N>
|
||||
concept has_eq
|
||||
= requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
|
||||
{ l == r; };
|
||||
|
||||
template<int N>
|
||||
concept has_ne
|
||||
= requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
|
||||
{ l != r; };
|
||||
|
||||
template<int N>
|
||||
concept has_lt
|
||||
= requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
|
||||
{ l < r; };
|
||||
|
||||
template<int N>
|
||||
concept has_gt
|
||||
= requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
|
||||
{ l > r; };
|
||||
|
||||
template<int N>
|
||||
concept has_le
|
||||
= requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
|
||||
{ l <= r; };
|
||||
|
||||
template<int N>
|
||||
concept has_ge
|
||||
= requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
|
||||
{ l >= r; };
|
||||
|
||||
static_assert( has_eq<0> );
|
||||
static_assert( ! has_eq<1> );
|
||||
static_assert( ! has_eq<2> );
|
||||
|
||||
static_assert( has_ne<0> ); // uses synthesized operator!=
|
||||
static_assert( ! has_ne<1> );
|
||||
static_assert( ! has_ne<2> );
|
||||
|
||||
static_assert( ! has_lt<0> );
|
||||
static_assert( has_lt<1> );
|
||||
static_assert( ! has_lt<2> );
|
||||
|
||||
static_assert( ! has_gt<0> );
|
||||
static_assert( ! has_gt<1> );
|
||||
static_assert( has_gt<2> );
|
||||
|
||||
static_assert( ! has_le<0> );
|
||||
static_assert( ! has_le<1> );
|
||||
static_assert( has_le<2> );
|
||||
|
||||
static_assert( ! has_ge<0> );
|
||||
static_assert( has_ge<1> );
|
||||
static_assert( ! has_ge<2> );
|
@ -0,0 +1,156 @@
|
||||
// Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <iterator>
|
||||
|
||||
template<int>
|
||||
struct Iter
|
||||
{
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = int;
|
||||
using pointer = int*;
|
||||
using reference = int&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
Iter();
|
||||
|
||||
Iter& operator++();
|
||||
Iter operator++(int);
|
||||
Iter& operator--();
|
||||
Iter operator--(int);
|
||||
int& operator*() const;
|
||||
int* operator->() const;
|
||||
|
||||
int& operator[](difference_type) const;
|
||||
|
||||
Iter& operator+=(difference_type);
|
||||
Iter& operator-=(difference_type);
|
||||
|
||||
template<int N> friend Iter operator+(Iter<N>, difference_type);
|
||||
template<int N> friend Iter operator+(difference_type, Iter<N>);
|
||||
template<int N> friend Iter operator-(Iter<N>, difference_type);
|
||||
template<int N> friend difference_type operator-(Iter<N>, Iter<N>);
|
||||
|
||||
// Define the full set of operators for same-type comparisons
|
||||
template<int N> friend bool operator==(Iter<N>, Iter<N>); // synthesizes !=
|
||||
template<int N> friend bool operator<(Iter<N>, Iter<N>);
|
||||
template<int N> friend bool operator>(Iter<N>, Iter<N>);
|
||||
template<int N> friend bool operator<=(Iter<N>, Iter<N>);
|
||||
template<int N> friend bool operator>=(Iter<N>, Iter<N>);
|
||||
};
|
||||
|
||||
static_assert( std::random_access_iterator<Iter<0>> );
|
||||
|
||||
// Define a single kind of mixed-type comparison for each specialization.
|
||||
int operator==(Iter<0>, long*);
|
||||
void* operator!=(Iter<1>, long*);
|
||||
bool& operator< (Iter<2>, long*);
|
||||
int operator> (Iter<3>, long*);
|
||||
void* operator<=(Iter<4>, long*);
|
||||
bool& operator>=(Iter<5>, long*);
|
||||
|
||||
using std::reverse_iterator;
|
||||
|
||||
reverse_iterator<Iter<0>> l0{Iter<0>()};
|
||||
reverse_iterator<Iter<1>> l1{Iter<1>()};
|
||||
reverse_iterator<Iter<2>> l2{Iter<2>()};
|
||||
reverse_iterator<Iter<3>> l3{Iter<3>()};
|
||||
reverse_iterator<Iter<4>> l4{Iter<4>()};
|
||||
reverse_iterator<Iter<5>> l5{Iter<5>()};
|
||||
reverse_iterator<long*> r{nullptr};
|
||||
|
||||
bool b0 = l0 == r;
|
||||
bool b1 = l1 != r;
|
||||
bool b2 = l2 < r;
|
||||
bool b3 = l3 > r;
|
||||
bool b4 = l4 <= r;
|
||||
bool b5 = l5 >= r;
|
||||
|
||||
template<int N>
|
||||
concept has_eq
|
||||
= requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
|
||||
{ l == r; };
|
||||
|
||||
template<int N>
|
||||
concept has_ne
|
||||
= requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
|
||||
{ l != r; };
|
||||
|
||||
template<int N>
|
||||
concept has_lt
|
||||
= requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
|
||||
{ l < r; };
|
||||
|
||||
template<int N>
|
||||
concept has_gt
|
||||
= requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
|
||||
{ l > r; };
|
||||
|
||||
template<int N>
|
||||
concept has_le
|
||||
= requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
|
||||
{ l <= r; };
|
||||
|
||||
template<int N>
|
||||
concept has_ge
|
||||
= requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
|
||||
{ l >= r; };
|
||||
|
||||
static_assert( has_eq<0> );
|
||||
static_assert( ! has_eq<1> );
|
||||
static_assert( ! has_eq<2> );
|
||||
static_assert( ! has_eq<3> );
|
||||
static_assert( ! has_eq<4> );
|
||||
static_assert( ! has_eq<5> );
|
||||
|
||||
static_assert( has_ne<0> ); // uses synthesized operator!=
|
||||
static_assert( has_ne<1> );
|
||||
static_assert( ! has_ne<2> );
|
||||
static_assert( ! has_ne<3> );
|
||||
static_assert( ! has_ne<4> );
|
||||
static_assert( ! has_ne<5> );
|
||||
|
||||
static_assert( ! has_lt<0> );
|
||||
static_assert( ! has_lt<1> );
|
||||
static_assert( has_lt<2> );
|
||||
static_assert( ! has_lt<3> );
|
||||
static_assert( ! has_lt<4> );
|
||||
static_assert( ! has_lt<5> );
|
||||
|
||||
static_assert( ! has_gt<0> );
|
||||
static_assert( ! has_gt<1> );
|
||||
static_assert( ! has_gt<2> );
|
||||
static_assert( has_gt<3> );
|
||||
static_assert( ! has_gt<4> );
|
||||
static_assert( ! has_gt<5> );
|
||||
|
||||
static_assert( ! has_le<0> );
|
||||
static_assert( ! has_le<1> );
|
||||
static_assert( ! has_le<2> );
|
||||
static_assert( ! has_le<3> );
|
||||
static_assert( has_le<4> );
|
||||
static_assert( ! has_le<5> );
|
||||
|
||||
static_assert( ! has_ge<0> );
|
||||
static_assert( ! has_ge<1> );
|
||||
static_assert( ! has_ge<2> );
|
||||
static_assert( ! has_ge<3> );
|
||||
static_assert( ! has_ge<4> );
|
||||
static_assert( has_ge<5> );
|
Loading…
x
Reference in New Issue
Block a user