Wow, I just noticed that the current wording allows tuple<> to be compared to any array<T, 0>, regardless of the type of T. However, tuple<T> can only be compared to array<T, 1> if T itself is comparable. This seems to be a defect.
Osama Abdelkader <[email protected]> 於 2025年10月17日 週五 下午11:27寫道: > Fixes #119721 > > This fixes a C++23 compliance issue where std::tuple<> cannot be compared > with std::array<T, 0>. Both are empty tuple-like types and should be > comparable according to the C++23 standard. > > The fix adds the missing comparison operators: > - operator== and operator!= (return true and false respectively) > - operator<, operator<=, operator>, operator>= (follow ordering rules for > empty types) > - operator<=> (returns strong_ordering::equal) > > This resolves the 'rejects-valid' bug where GCC was rejecting valid C++23 > code > that Clang with libc++ already supports correctly. > > libstdc++-v3/ChangeLog: > > * include/std/tuple: Add comparison operators between tuple<> and > array<T, 0>. > > Signed-off-by: Osama Abdelkader <[email protected]> > --- > libstdc++-v3/include/std/tuple | 88 ++++++++++++++++++++++++++++++++++ > 1 file changed, 88 insertions(+) > > diff --git a/libstdc++-v3/include/std/tuple > b/libstdc++-v3/include/std/tuple > index 0ca616f1b..d3621dd16 100644 > --- a/libstdc++-v3/include/std/tuple > +++ b/libstdc++-v3/include/std/tuple > @@ -1880,6 +1880,94 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > using _Cat = typename > __tuple_like_common_comparison_category<_UTuple>::type; > return std::__tuple_cmp<_Cat>(__t, __u, > index_sequence_for<_Elements...>()); > } > + > + // Comparison operators between tuple<> and array<T, 0> > + // These are needed because both are empty tuple-like types in C++23 > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator==(const tuple<>&, const array<_Tp, 0>&) > + { return true; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator==(const array<_Tp, 0>&, const tuple<>&) > + { return true; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator!=(const tuple<>&, const array<_Tp, 0>&) > + { return false; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator!=(const array<_Tp, 0>&, const tuple<>&) > + { return false; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator<(const tuple<>&, const array<_Tp, 0>&) > + { return false; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator<(const array<_Tp, 0>&, const tuple<>&) > + { return false; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator<=(const tuple<>&, const array<_Tp, 0>&) > + { return true; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator<=(const array<_Tp, 0>&, const tuple<>&) > + { return true; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator>(const tuple<>&, const array<_Tp, 0>&) > + { return false; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator>(const array<_Tp, 0>&, const tuple<>&) > + { return false; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator>=(const tuple<>&, const array<_Tp, 0>&) > + { return true; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr bool > + operator>=(const array<_Tp, 0>&, const tuple<>&) > + { return true; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr strong_ordering > + operator<=>(const tuple<>&, const array<_Tp, 0>&) > + { return strong_ordering::equal; } > + > + template<typename _Tp> > + [[nodiscard]] > + constexpr strong_ordering > + operator<=>(const array<_Tp, 0>&, const tuple<>&) > + { return strong_ordering::equal; } > + > #endif // C++23 > > #else // ! (concepts && consteval) > -- > 2.43.0 > >
