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);


> 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
>>>>
>>>>

Reply via email to