As suggested by Jason, this makes all __normal_iterator operators into
friends so they can be found by ADL and don't need to be separately
exported in module std.
For the operator<=> comparing two iterators of the same type, I had to
use a deduced return type and add a requires-clause, because it's no
longer a template and so we no longer get substitution failures when
it's considered in oerload resolution.
I also had to reorder the __attribute__((always_inline)) and
[[nodiscard]] attributes, which have to be in a particular order when
used on friend functions.
libstdc++-v3/ChangeLog:
* include/bits/stl_iterator.h (__normal_iterator): Make all
non-member operators hidden friends.
* src/c++11/string-inst.cc: Remove explicit instantiations of
operators that are no longer templates.
---
Tested x86_64-linux.
This iterator type isn't defined in the standard, and users shouldn't be
doing funny things with it, so nothing prevents us from replacing its
operators with hidden friends.
libstdc++-v3/include/bits/stl_iterator.h | 341 ++++++++++++-----------
libstdc++-v3/src/c++11/string-inst.cc | 11 -
2 files changed, 184 insertions(+), 168 deletions(-)
diff --git a/libstdc++-v3/include/bits/stl_iterator.h
b/libstdc++-v3/include/bits/stl_iterator.h
index e872598d7d8..656a47e5f76 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1164,188 +1164,215 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
const _Iterator&
base() const _GLIBCXX_NOEXCEPT
{ return _M_current; }
- };
- // Note: In what follows, the left- and right-hand-side iterators are
- // allowed to vary in types (conceptually in cv-qualification) so that
- // comparison between cv-qualified and non-cv-qualified iterators be
- // valid. However, the greedy and unfriendly operators in std::rel_ops
- // will make overload resolution ambiguous (when in scope) if we don't
- // provide overloads whose operands are of the same type. Can someone
- // remind me what generic programming is about? -- Gaby
+ private:
+ // Note: In what follows, the left- and right-hand-side iterators are
+ // allowed to vary in types (conceptually in cv-qualification) so that
+ // comparison between cv-qualified and non-cv-qualified iterators be
+ // valid. However, the greedy and unfriendly operators in std::rel_ops
+ // will make overload resolution ambiguous (when in scope) if we don't
+ // provide overloads whose operands are of the same type. Can someone
+ // remind me what generic programming is about? -- Gaby
#ifdef __cpp_lib_three_way_comparison
- template<typename _IteratorL, typename _IteratorR, typename _Container>
- [[nodiscard, __gnu__::__always_inline__]]
- constexpr bool
- operator==(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs)
- noexcept(noexcept(__lhs.base() == __rhs.base()))
- requires requires {
- { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>;
- }
- { return __lhs.base() == __rhs.base(); }
+ template<typename _Iter>
+ [[nodiscard, __gnu__::__always_inline__]]
+ friend
+ constexpr bool
+ operator==(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs)
+ noexcept(noexcept(__lhs.base() == __rhs.base()))
+ requires requires {
+ { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>;
+ }
+ { return __lhs.base() == __rhs.base(); }
- template<typename _IteratorL, typename _IteratorR, typename _Container>
- [[nodiscard, __gnu__::__always_inline__]]
- constexpr std::__detail::__synth3way_t<_IteratorR, _IteratorL>
- operator<=>(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs)
- noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base())))
- { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); }
+ template<typename _Iter>
+ static constexpr bool __nothrow_synth3way
+ = noexcept(std::__detail::__synth3way(std::declval<_Iterator&>(),
+ std::declval<_Iter&>()));
- template<typename _Iterator, typename _Container>
- [[nodiscard, __gnu__::__always_inline__]]
- constexpr bool
- operator==(const __normal_iterator<_Iterator, _Container>& __lhs,
- const __normal_iterator<_Iterator, _Container>& __rhs)
- noexcept(noexcept(__lhs.base() == __rhs.base()))
- requires requires {
- { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>;
- }
- { return __lhs.base() == __rhs.base(); }
+ template<typename _Iter>
+ [[nodiscard, __gnu__::__always_inline__]]
+ friend
+ constexpr std::__detail::__synth3way_t<_Iterator, _Iter>
+ operator<=>(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs)
+ noexcept(__nothrow_synth3way<_Iter>)
+ requires requires {
+ std::__detail::__synth3way(__lhs.base(), __rhs.base());
+ }
+ { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); }
- template<typename _Iterator, typename _Container>
- [[nodiscard, __gnu__::__always_inline__]]
- constexpr std::__detail::__synth3way_t<_Iterator>
- operator<=>(const __normal_iterator<_Iterator, _Container>& __lhs,
- const __normal_iterator<_Iterator, _Container>& __rhs)
- noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base())))
- { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); }
+ [[nodiscard, __gnu__::__always_inline__]]
+ friend
+ constexpr bool
+ operator==(const __normal_iterator& __lhs, const __normal_iterator&
__rhs)
+ noexcept(noexcept(__lhs.base() == __rhs.base()))
+ requires requires {
+ { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>;
+ }
+ { return __lhs.base() == __rhs.base(); }
+
+ [[nodiscard, __gnu__::__always_inline__]]
+ friend
+ constexpr auto
+ operator<=>(const __normal_iterator& __lhs,
+ const __normal_iterator& __rhs)
+ noexcept(__nothrow_synth3way<_Iterator>)
+ requires requires {
+ std::__detail::__synth3way(__lhs.base() == __rhs.base());
+ }
+ { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); }
#else
- // Forward iterator requirements
- template<typename _IteratorL, typename _IteratorR, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator==(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() == __rhs.base(); }
+ // Forward iterator requirements
+ template<typename _Iter>
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline bool
+ operator==(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() == __rhs.base(); }
- template<typename _Iterator, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator==(const __normal_iterator<_Iterator, _Container>& __lhs,
- const __normal_iterator<_Iterator, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() == __rhs.base(); }
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline bool
+ operator==(const __normal_iterator& __lhs, const __normal_iterator&
__rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() == __rhs.base(); }
- template<typename _IteratorL, typename _IteratorR, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator!=(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() != __rhs.base(); }
+ template<typename _Iter>
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline bool
+ operator!=(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() != __rhs.base(); }
- template<typename _Iterator, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator!=(const __normal_iterator<_Iterator, _Container>& __lhs,
- const __normal_iterator<_Iterator, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() != __rhs.base(); }
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline bool
+ operator!=(const __normal_iterator& __lhs, const __normal_iterator&
__rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() != __rhs.base(); }
- // Random access iterator requirements
- template<typename _IteratorL, typename _IteratorR, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator<(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() < __rhs.base(); }
+ // Random access iterator requirements
+ template<typename _Iter>
+ friend
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR
+ inline bool
+ operator<(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() < __rhs.base(); }
- template<typename _Iterator, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR
- inline bool
- operator<(const __normal_iterator<_Iterator, _Container>& __lhs,
- const __normal_iterator<_Iterator, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() < __rhs.base(); }
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX20_CONSTEXPR
+ inline bool
+ operator<(const __normal_iterator& __lhs, const __normal_iterator& __rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() < __rhs.base(); }
- template<typename _IteratorL, typename _IteratorR, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator>(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() > __rhs.base(); }
+ template<typename _Iter>
+ friend
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR
+ inline bool
+ operator>(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() > __rhs.base(); }
- template<typename _Iterator, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator>(const __normal_iterator<_Iterator, _Container>& __lhs,
- const __normal_iterator<_Iterator, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() > __rhs.base(); }
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline bool
+ operator>(const __normal_iterator& __lhs, const __normal_iterator& __rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() > __rhs.base(); }
- template<typename _IteratorL, typename _IteratorR, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() <= __rhs.base(); }
+ template<typename _Iter>
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline bool
+ operator<=(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() <= __rhs.base(); }
- template<typename _Iterator, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator<=(const __normal_iterator<_Iterator, _Container>& __lhs,
- const __normal_iterator<_Iterator, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() <= __rhs.base(); }
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline bool
+ operator<=(const __normal_iterator& __lhs, const __normal_iterator&
__rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() <= __rhs.base(); }
- template<typename _IteratorL, typename _IteratorR, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() >= __rhs.base(); }
+ template<typename _Iter>
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline bool
+ operator>=(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() >= __rhs.base(); }
- template<typename _Iterator, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline bool
- operator>=(const __normal_iterator<_Iterator, _Container>& __lhs,
- const __normal_iterator<_Iterator, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() >= __rhs.base(); }
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline bool
+ operator>=(const __normal_iterator& __lhs, const __normal_iterator&
__rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() >= __rhs.base(); }
#endif // three-way comparison
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // According to the resolution of DR179 not only the various comparison
- // operators but also operator- must accept mixed iterator/const_iterator
- // parameters.
- template<typename _IteratorL, typename _IteratorR, typename _Container>
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 179. Comparison of const_iterators to iterators doesn't work
+ // According to the resolution of DR179 not only the various comparison
+ // operators but also operator- must accept mixed iterator/const_iterator
+ // parameters.
+ template<typename _Iter>
#if __cplusplus >= 201103L
- // DR 685.
- [[__nodiscard__, __gnu__::__always_inline__]]
- constexpr auto
- operator-(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs) noexcept
- -> decltype(__lhs.base() - __rhs.base())
+ [[__nodiscard__, __gnu__::__always_inline__]]
+ friend
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 685. reverse_iterator/move_iterator difference has invalid signatures
+ constexpr auto
+ operator-(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs) noexcept
+ -> decltype(__lhs.base() - __rhs.base())
#else
- inline typename __normal_iterator<_IteratorL, _Container>::difference_type
- operator-(const __normal_iterator<_IteratorL, _Container>& __lhs,
- const __normal_iterator<_IteratorR, _Container>& __rhs)
+ friend
+ difference_type
+ operator-(const __normal_iterator& __lhs,
+ const __normal_iterator<_Iter, _Container>& __rhs)
#endif
- { return __lhs.base() - __rhs.base(); }
+ { return __lhs.base() - __rhs.base(); }
- template<typename _Iterator, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline typename __normal_iterator<_Iterator, _Container>::difference_type
- operator-(const __normal_iterator<_Iterator, _Container>& __lhs,
- const __normal_iterator<_Iterator, _Container>& __rhs)
- _GLIBCXX_NOEXCEPT
- { return __lhs.base() - __rhs.base(); }
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline difference_type
+ operator-(const __normal_iterator& __lhs, const __normal_iterator& __rhs)
+ _GLIBCXX_NOEXCEPT
+ { return __lhs.base() - __rhs.base(); }
- template<typename _Iterator, typename _Container>
- _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
- inline __normal_iterator<_Iterator, _Container>
- operator+(typename __normal_iterator<_Iterator,
_Container>::difference_type
- __n, const __normal_iterator<_Iterator, _Container>& __i)
- _GLIBCXX_NOEXCEPT
- { return __normal_iterator<_Iterator, _Container>(__i.base() + __n); }
+ __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+ friend
+ _GLIBCXX_CONSTEXPR
+ inline __normal_iterator
+ operator+(difference_type __n, const __normal_iterator& __i)
+ _GLIBCXX_NOEXCEPT
+ { return __normal_iterator(__i.base() + __n); }
+ };
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace __gnu_cxx
diff --git a/libstdc++-v3/src/c++11/string-inst.cc
b/libstdc++-v3/src/c++11/string-inst.cc
index ec5ba41ebcd..b8806304949 100644
--- a/libstdc++-v3/src/c++11/string-inst.cc
+++ b/libstdc++-v3/src/c++11/string-inst.cc
@@ -110,14 +110,3 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
-
-namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
- using std::S;
- template bool operator==(const S::iterator&, const S::iterator&);
- template bool operator==(const S::const_iterator&, const S::const_iterator&);
-
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace
--
2.47.0