[PATCH v5] libstdc++: Add comparison operators between tuple<> and array<T, 0>
Tomasz Kaminski
tkaminsk@redhat.com
Mon Oct 20 15:38:11 GMT 2025
On Mon, Oct 20, 2025 at 5:17 PM Osama Abdelkader <osama.abdelkader@gmail.com>
wrote:
> This fixes the C++23 compliance issue where std::tuple<> cannot be compared
> with other empty tuple-like types such as std::array<T, 0>.
>
> The operators correctly allow comparison with array<T, 0> even when T is
> not
> comparable, because empty tuple-like types don't compare element values.
>
> libstdc++-v3/ChangeLog:
>
> PR libstdc++/119721
> * include/std/tuple: Add tuple<> comparison operators for
> empty tuple-like types.
> * testsuite/23_containers/tuple/comparison_operators/119721.cc:
> New test.
>
> Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
> ---
> v5:
> - made the operators hidden friends
> v4:
> - Added testsuite test
> v3:
> - Added noexcept specifiers to the operators
> v2:
> - Replaced explicit array<T, 0> operators with generic tuple-like operators
> - Only operator== and operator<=> are provided
> - Operators work with any empty tuple-like type
> - No need for reversed argument order
> ---
> libstdc++-v3/include/std/tuple | 19 +++++
> .../tuple/comparison_operators/119721.cc | 71 +++++++++++++++++++
> 2 files changed, 90 insertions(+)
> create mode 100644
> libstdc++-v3/testsuite/23_containers/tuple/comparison_operators/119721.cc
>
> diff --git a/libstdc++-v3/include/std/tuple
> b/libstdc++-v3/include/std/tuple
> index 0ca616f1b..b287694cc 100644
> --- a/libstdc++-v3/include/std/tuple
> +++ b/libstdc++-v3/include/std/tuple
> @@ -1999,6 +1999,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> template<typename _Alloc>
> _GLIBCXX20_CONSTEXPR
> tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept { }
> +
> +#if __cpp_lib_tuple_like // >= C++23
> + // Comparison operators for tuple<> with other empty tuple-like
> types
> + // Note: These operators allow comparison with any empty tuple-like
> type,
> + // including array<T, 0>, where T may not be comparable.
> + // This is correct because empty tuple-like types don't compare
> elements.
> + template<__tuple_like _UTuple>
> + requires (!__is_tuple_v<_UTuple> && tuple_size_v<_UTuple> == 0)
> + [[nodiscard]]
> + friend constexpr bool
> + operator==(const tuple&, const _UTuple&) noexcept
> + { return true; }
> +
> + template<__tuple_like _UTuple>
> + requires (!__is_tuple_v<_UTuple> && tuple_size_v<_UTuple> == 0)
> + friend constexpr strong_ordering
> + operator<=>(const tuple&, const _UTuple&) noexcept
> + { return strong_ordering::equal; }
> +#endif // C++23
> };
>
> #if !(__cpp_concepts && __cpp_consteval && __cpp_conditional_explicit) //
> !C++20
> diff --git
> a/libstdc++-v3/testsuite/23_containers/tuple/comparison_operators/119721.cc
> b/libstdc++-v3/testsuite/23_containers/tuple/comparison_operators/119721.cc
> new file mode 100644
> index 000000000..711874acf
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/tuple/comparison_operators/119721.cc
> @@ -0,0 +1,71 @@
> +// { dg-do compile { target c++23 } }
> +// { dg-options "-std=c++23" }
> +
> +// Test for PR libstdc++/119721: tuple<> comparison with array<T, 0>
> +
> +#include <tuple>
> +#include <array>
> +#include <cassert>
> +
> +void test01()
>
You do noeed to update this test, but there is a simpler way of testing
constexpr evaluation. Declare the function as
constexpr bool
test01() {
[...]
return true;
};
And then inside main, do:
test01();
static_assert(test01());
Or for multiple test functions (also you do not need to adjust return type).
auto test_all = [] {
test01();
test02();
return true;
};
test_all();
static_assert(test_all());
> +{
> + std::tuple<> t;
> + std::array<int, 0> a;
> +
> + // Basic comparison should work
> + assert(t == a);
> + assert(a == t);
> + assert(!(t != a));
> + assert(!(a != t));
> +
> + // Ordering comparisons should be equal
> + assert(!(t < a));
> + assert(!(t > a));
> + assert(t <= a);
> + assert(t >= a);
> + assert(!(a < t));
> + assert(!(a > t));
> + assert(a <= t);
> + assert(a >= t);
> +
> + // Three-way comparison should return equal
> + assert((t <=> a) == std::strong_ordering::equal);
> + assert((a <=> t) == std::strong_ordering::equal);
> +}
> +
> +void test02()
> +{
> + // Test with non-comparable element type
> + struct NonComparable {
> + void operator==(const NonComparable&) const = delete;
> + void operator<=>(const NonComparable&) const = delete;
> + };
> +
> + std::tuple<> t;
> + std::array<NonComparable, 0> a;
> +
> + // Should still work because empty containers don't compare elements
> + assert(t == a);
> + assert((t <=> a) == std::strong_ordering::equal);
> +}
> +
> +void test03()
> +{
> + // Test constexpr evaluation
> + constexpr std::tuple<> t;
> + constexpr std::array<int, 0> a;
> +
> + constexpr bool eq = t == a;
> + constexpr auto cmp = t <=> a;
> +
> + static_assert(eq == true);
> + static_assert(cmp == std::strong_ordering::equal);
> +}
> +
> +int main()
> +{
> + test01();
> + test02();
> + test03();
> + return 0;
> +}
> --
> 2.43.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20251020/41acb5bb/attachment.htm>
More information about the Libstdc++
mailing list