On Fri, Oct 17, 2025 at 6:33 PM Tomasz Kaminski <[email protected]> wrote:
> > > On Fri, Oct 17, 2025 at 6:27 PM Hewill Kang <[email protected]> wrote: > >> I'm not sure what you mean, but it does weird to me that the underlying >> types can't be compared, but the corresponding tuple-like can be compared: >> >> #include <tuple> >> #include <array> >> >> struct S { >> void operator== (const S&) const = delete; >> void operator<=>(const S&) const = delete; >> void operator <(const S&) const = delete; >> }; >> >> int main() { >> std::tuple<> t; >> std::array<S, 0> a; >> // a == a; // error >> t < a; // ok >> > Yes, because the < is doing more efficient implementation of: > t < std::tuple<>(a); > And this constructor alos does not look on a, and it can be non-movable. I think this is more a problem of array<S, 0> not being comparable, despite being copyable regardless of S. > > >> t == a; // ok >> t <=> a; // ok >> } >> >> Tomasz Kaminski <[email protected]> 於 2025年10月18日 週六 上午12:20寫道: >> >>> >>> >>> On Fri, Oct 17, 2025 at 6:00 PM Hewill Kang <[email protected]> wrote: >>> >>>> 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. >>>> >>> They common_reference is tuple<>, but they are not totally_ordered_with, >>> as array is not ordered. >>> >>>> 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 >>>>> >>>>>
