Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2226339/?format=api
{ "id": 2226339, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2226339/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhubxss5wg.gcc.gcc-TEST.peppe.34.1.1@forge-stage.sourceware.org/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/1.2/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<bmm.hhubxss5wg.gcc.gcc-TEST.peppe.34.1.1@forge-stage.sourceware.org>", "list_archive_url": null, "date": "2026-04-22T10:50:43", "name": "[v1,1/1] libstdc++: implement tuple protocol for std::complex (P2819R2)", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "6b3b0166fe7891c9bede96530f8615c7501a7efa", "submitter": { "id": 93222, "url": "http://patchwork.ozlabs.org/api/1.2/people/93222/?format=api", "name": "peppe via Sourceware Forge", "email": "forge-bot+peppe@forge-stage.sourceware.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhubxss5wg.gcc.gcc-TEST.peppe.34.1.1@forge-stage.sourceware.org/mbox/", "series": [ { "id": 500993, "url": "http://patchwork.ozlabs.org/api/1.2/series/500993/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=500993", "date": "2026-04-22T10:50:42", "name": "WIP: libstdc++: implement tuple protocol for std::complex (P2819R2)", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/500993/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2226339/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2226339/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org; dmarc=none (p=none dis=none)\n header.from=forge-stage.sourceware.org", "sourceware.org;\n spf=pass smtp.mailfrom=forge-stage.sourceware.org", "server2.sourceware.org;\n arc=none smtp.remote-ip=38.145.34.39" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g0xwf5q20z1yD5\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 21:35:14 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 6731D43492E6\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 11:35:12 +0000 (GMT)", "from forge-stage.sourceware.org (vm08.sourceware.org [38.145.34.39])\n by sourceware.org (Postfix) with ESMTPS id 130A44BBC082\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 10:51:40 +0000 (GMT)", "from forge-stage.sourceware.org (localhost [IPv6:::1])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256)\n (No client certificate requested)\n by forge-stage.sourceware.org (Postfix) with ESMTPS id DB3C742BE0\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 10:51:39 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 6731D43492E6", "OpenDKIM Filter v2.11.0 sourceware.org 130A44BBC082" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 130A44BBC082", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 130A44BBC082", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776855100; cv=none;\n b=WXuAaNByL1aGTHAb9BGoAM2ybNj/ZH6nT2Pz664LP6f2QV8Q6RcDYCUBEEZC2KrPUCVMV8HPpQH7oAL9wQWREDwcak0EjVk67YoteMnoIxuQQQbKgN0VKRYdAR7exFJwwc6PRo9PpThGZqZfmVigxjCTYa8lnUK3ljIknTsouSY=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776855100; c=relaxed/simple;\n bh=gB719swXN62ZTF4pltX3jLQpiGk12hNIM+fJSg6yw5M=;\n h=From:Date:Subject:To:Message-ID;\n b=LSXxQhM+uQC5Pr5K3cVctZAdfxSfRCl3ysuFhlvRq/I7yQU8T1jUtBSLHMP6h+qNOhvWQ4ZEKcT1Ljb0kNaUg1tZAXKXIZXuzJic1gWwBrzGP94T45JXxjyVruBrKlsn/2hdKEvbCreiopo1JqWE2Ukx8aTlg8N7Geo/XEpRChU=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "From": "peppe via Sourceware Forge <forge-bot+peppe@forge-stage.sourceware.org>", "Date": "Wed, 22 Apr 2026 10:50:43 +0000", "Subject": "[PATCH v1 1/1] libstdc++: implement tuple protocol for std::complex\n (P2819R2)", "To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>", "Message-ID": "\n <bmm.hhubxss5wg.gcc.gcc-TEST.peppe.34.1.1@forge-stage.sourceware.org>", "X-Mailer": "batrachomyomachia", "X-Pull-Request-Organization": "gcc", "X-Pull-Request-Repository": "gcc-TEST", "X-Pull-Request": "https://forge.sourceware.org/gcc/gcc-TEST/pulls/34", "References": "\n <bmm.hhubxss5wg.gcc.gcc-TEST.peppe.34.1.0@forge-stage.sourceware.org>", "In-Reply-To": "\n <bmm.hhubxss5wg.gcc.gcc-TEST.peppe.34.1.0@forge-stage.sourceware.org>", "X-Patch-URL": "\n https://forge.sourceware.org/peppe/gcc-TEST/commit/601a2df924b7bd13b21c7ee1af3f4531313a2409", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Reply-To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>,\n peppe@noreply.localhost", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "From: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>\n\nThis commit implements P2819R2 for C++26, making std::complex\ndestructurable and tuple-like (see [complex.tuple]).\n\nstd::get needs to get forward declared in stl_pair.h (following the\nexisting precedent for the implementation of P2165R4, cf.\nr14-8710-g65b4cba9d6a9ff), and implemented in <complex>.\n\nAlso, std::get(complex<T>) needs to return *references* to the real and\nimaginary parts of a std::complex object, honoring the value category\nand constness of the argument. In principle a straightforward task, it\ngets a bit convoluted by the fact that:\n\n1) std::complex does not have existing getters that one can use for this\n(real() and imag() return values, not references);\n\n2) there are specializations for language/extended floating-point types,\nwhich requires some duplication -- need to amend the primary and all\nthe specializations;\n\n3) these specializations use a `__complex__ T`, but the primary template\nuses two non-static data members, making generic code harder to write.\n\nThe implementation choice used here is to add the overloads of std::get\nfor complex as declared in [complex.tuple]. In turn they dispatch to a\nnewly added getter that extracts references to the real/imaginary parts\nof a complex<T>. This getter is private API, and the implementation\ndepends on whether it's the primary (bind the data member) or a\nspecialization (use the GCC language extensions for __complex__).\nTo avoid duplication and minimize template instantiations, the getter\nuses C++23's deducing this (this avoids const overloads). The value\ncategory is dealt with by the std::get overloads.\n\nAdd a test that covers the aspects of the tuple protocol, as well as the\ntuple-like interface. While at it, add a test for the existing\ntuple-like feature-testing macro.\n\n\tPR libstdc++/113310\n\nlibstdc++-v3/ChangeLog:\n\n\t* include/bits/stl_pair.h (get): Forward-declare std::get for\n\tstd::complex.\n\t* include/bits/version.def (tuple_like): Bump the value of\n\tthe feature-testing macro in C++26.\n\t* include/bits/version.h: Regenerate.\n\t* include/std/complex: Implement the tuple protocol for\n\tstd::complex.\n\t(tuple_size): Specialize for std::complex.\n\t(tuple_element): Ditto.\n\t(__is_tuple_like_v): Ditto.\n\t(complex): Add a private getter to obtain references to the real\n\tand the imaginary part, on the primary class template and on its\n\tspecializations.\n\t(get): Add overloads of std::get for std::complex.\n\t* testsuite/20_util/tuple/tuple_like_ftm.cc: New test.\n\t* testsuite/26_numerics/complex/tuple_like.cc: New test.\n---\n libstdc++-v3/include/bits/stl_pair.h | 18 ++\n libstdc++-v3/include/bits/version.def | 5 +\n libstdc++-v3/include/bits/version.h | 7 +-\n libstdc++-v3/include/std/complex | 91 +++++++++\n .../testsuite/20_util/tuple/tuple_like_ftm.cc | 17 ++\n .../26_numerics/complex/tuple_like.cc | 179 ++++++++++++++++++\n 6 files changed, 316 insertions(+), 1 deletion(-)\n create mode 100644 libstdc++-v3/testsuite/20_util/tuple/tuple_like_ftm.cc\n create mode 100644 libstdc++-v3/testsuite/26_numerics/complex/tuple_like.cc", "diff": "diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h\nindex c57e3c097652..8c57712b4617 100644\n--- a/libstdc++-v3/include/bits/stl_pair.h\n+++ b/libstdc++-v3/include/bits/stl_pair.h\n@@ -101,6 +101,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n template<size_t...>\n struct _Index_tuple;\n \n+ template<typename _Tp>\n+ class complex;\n+\n template<size_t _Int, class _Tp1, class _Tp2>\n constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&\n get(pair<_Tp1, _Tp2>& __in) noexcept;\n@@ -149,6 +152,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n constexpr const _Tp&&\n get(const array<_Tp, _Nm>&&) noexcept;\n \n+#if __glibcxx_tuple_like >= 202311 // >= C++26\n+ template<size_t _Int, typename _Tp>\n+ constexpr _Tp&\n+ get(complex<_Tp>&) noexcept;\n+ template<size_t _Int, typename _Tp>\n+ constexpr _Tp&&\n+ get(complex<_Tp>&&) noexcept;\n+ template<size_t _Int, typename _Tp>\n+ constexpr const _Tp&\n+ get(const complex<_Tp>&) noexcept;\n+ template<size_t _Int, typename _Tp>\n+ constexpr const _Tp&&\n+ get(const complex<_Tp>&&) noexcept;\n+#endif\n+\n #if ! __cpp_lib_concepts\n // Concept utility functions, reused in conditionally-explicit\n // constructors.\ndiff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def\nindex 0cdc2e82fc55..71785fd683ff 100644\n--- a/libstdc++-v3/include/bits/version.def\n+++ b/libstdc++-v3/include/bits/version.def\n@@ -1797,6 +1797,11 @@ ftms = {\n \n ftms = {\n name = tuple_like;\n+ values = {\n+ v = 202311;\n+ cxxmin = 26;\n+ extra_cond = \"__cpp_explicit_this_parameter >= 202110L\";\n+ };\n values = {\n v = 202207;\n cxxmin = 23;\ndiff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h\nindex ec52cba517fa..01bbe448e779 100644\n--- a/libstdc++-v3/include/bits/version.h\n+++ b/libstdc++-v3/include/bits/version.h\n@@ -1986,7 +1986,12 @@\n #undef __glibcxx_want_to_underlying\n \n #if !defined(__cpp_lib_tuple_like)\n-# if (__cplusplus >= 202100L)\n+# if (__cplusplus > 202302L) && (__cpp_explicit_this_parameter >= 202110L)\n+# define __glibcxx_tuple_like 202311L\n+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_tuple_like)\n+# define __cpp_lib_tuple_like 202311L\n+# endif\n+# elif (__cplusplus >= 202100L)\n # define __glibcxx_tuple_like 202207L\n # if defined(__glibcxx_want_all) || defined(__glibcxx_want_tuple_like)\n # define __cpp_lib_tuple_like 202207L\ndiff --git a/libstdc++-v3/include/std/complex b/libstdc++-v3/include/std/complex\nindex 289a144cd7ed..59ef9057c418 100644\n--- a/libstdc++-v3/include/std/complex\n+++ b/libstdc++-v3/include/std/complex\n@@ -59,8 +59,14 @@\n \n #define __glibcxx_want_constexpr_complex\n #define __glibcxx_want_complex_udls\n+#define __glibcxx_want_tuple_like\n #include <bits/version.h>\n \n+#if __glibcxx_tuple_like >= 202311 // >= C++26\n+# include <bits/utility.h> // for tuple_element_t\n+# include <bits/stl_pair.h> // for __is_tuple_like_v\n+#endif\n+\n namespace std _GLIBCXX_VISIBILITY(default)\n {\n _GLIBCXX_BEGIN_NAMESPACE_VERSION\n@@ -123,6 +129,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n /// Return complex hyperbolic tangent of @a z.\n template<typename _Tp> complex<_Tp> tanh(const complex<_Tp>&);\n \n+#if __glibcxx_tuple_like >= 202311L // >= C++26\n+ template<typename _Tp>\n+ struct tuple_size<complex<_Tp>>\n+ : public integral_constant<size_t, 2> { };\n+ template<typename _Tp>\n+ struct tuple_element<0, complex<_Tp>>\n+ { using type = _Tp; };\n+ template<typename _Tp>\n+ struct tuple_element<1, complex<_Tp>>\n+ { using type = _Tp; };\n+ template<typename _Tp>\n+ inline constexpr bool __is_tuple_like_v<complex<_Tp>> = true;\n+#endif // __glibcxx_tuple_like >= 202311\n \n // 26.2.2 Primary template class complex\n /**\n@@ -244,6 +263,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n _GLIBCXX_CONSTEXPR complex __rep() const\n { return *this; }\n \n+#if __glibcxx_tuple_like >= 202311L // >= C++26\n+ template<typename _Cp>\n+ [[__gnu__::__always_inline__]]\n+ constexpr auto&\n+ __get_part(this _Cp& __z, size_t __i) noexcept\n+ {\n+\treturn __i == 0 ? __z._M_real : __z._M_imag;\n+ }\n+#endif\n+\n private:\n _Tp _M_real;\n _Tp _M_imag;\n@@ -608,6 +637,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n { return __z.imag(); }\n #endif\n \n+#if __glibcxx_tuple_like >= 202311L // >= C++26\n+ template<size_t _Int, typename _Tp>\n+ [[nodiscard,__gnu__::__always_inline__]]\n+ constexpr _Tp&\n+ get(complex<_Tp>& __z) noexcept\n+ {\n+ static_assert(_Int < 2);\n+ return __z.__get_part(_Int);\n+ }\n+\n+ template<size_t _Int, typename _Tp>\n+ [[nodiscard,__gnu__::__always_inline__]]\n+ constexpr _Tp&&\n+ get(complex<_Tp>&& __z) noexcept\n+ {\n+ static_assert(_Int < 2);\n+ return std::move(__z.__get_part(_Int));\n+ }\n+\n+ template<size_t _Int, typename _Tp>\n+ [[nodiscard,__gnu__::__always_inline__]]\n+ constexpr const _Tp&\n+ get(const complex<_Tp>& __z) noexcept\n+ {\n+ static_assert(_Int < 2);\n+ return __z.__get_part(_Int);\n+ }\n+\n+ template<size_t _Int, typename _Tp>\n+ [[nodiscard,__gnu__::__always_inline__]]\n+ constexpr const _Tp&&\n+ get(const complex<_Tp>&& __z) noexcept\n+ {\n+ static_assert(_Int < 2);\n+ return std::move(__z.__get_part(_Int));\n+ }\n+#endif // __glibcxx_tuple_like >= 202311\n+\n #if _GLIBCXX_USE_C99_COMPLEX\n #if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)\n inline _Float16\n@@ -1348,6 +1415,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \t : std::pow(complex<_Tp>(__x), __y);\n }\n \n+#if __glibcxx_tuple_like >= 202311L // >= C++26\n+#define _GLIBCXX26_DECLARE_COMPLEX_TUPLE_HELPER_ACCESSOR \\\n+ template<typename _Cp> \\\n+ [[__gnu__::__always_inline__]] \\\n+ constexpr auto& \\\n+ __get_part(this _Cp& __z, size_t __i) noexcept \\\n+ { \\\n+ return __i == 0 ? __real__ __z._M_value \\\n+\t : __imag__ __z._M_value; \\\n+ }\n+#else\n+#define _GLIBCXX26_DECLARE_COMPLEX_TUPLE_HELPER_ACCESSOR\n+#endif\n+\n /// 26.2.3 complex specializations\n /// complex<float> specialization\n template<>\n@@ -1501,6 +1582,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \n _GLIBCXX_CONSTEXPR _ComplexT __rep() const { return _M_value; }\n \n+ _GLIBCXX26_DECLARE_COMPLEX_TUPLE_HELPER_ACCESSOR\n+\n private:\n _ComplexT _M_value;\n };\n@@ -1658,6 +1741,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \n _GLIBCXX_CONSTEXPR _ComplexT __rep() const { return _M_value; }\n \n+ _GLIBCXX26_DECLARE_COMPLEX_TUPLE_HELPER_ACCESSOR\n+\n private:\n _ComplexT _M_value;\n };\n@@ -1817,6 +1902,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \n _GLIBCXX_CONSTEXPR _ComplexT __rep() const { return _M_value; }\n \n+ _GLIBCXX26_DECLARE_COMPLEX_TUPLE_HELPER_ACCESSOR\n+\n private:\n _ComplexT _M_value;\n };\n@@ -1971,11 +2058,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \n constexpr _ComplexT __rep() const { return _M_value; }\n \n+ _GLIBCXX26_DECLARE_COMPLEX_TUPLE_HELPER_ACCESSOR\n+\n private:\n _ComplexT _M_value;\n };\n #endif\n \n+#undef _GLIBCXX26_DECLARE_COMPLEX_TUPLE_HELPER_ACCESSOR\n+\n #if __cplusplus <= 202002L\n // These bits have to be at the end of this file, so that the\n // specializations have all been defined.\ndiff --git a/libstdc++-v3/testsuite/20_util/tuple/tuple_like_ftm.cc b/libstdc++-v3/testsuite/20_util/tuple/tuple_like_ftm.cc\nnew file mode 100644\nindex 000000000000..d7399b506eab\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/20_util/tuple/tuple_like_ftm.cc\n@@ -0,0 +1,17 @@\n+// { dg-do preprocess { target c++23 } }\n+// { dg-add-options no_pch }\n+\n+#include <utility>\n+\n+#if !defined(__cpp_lib_tuple_like)\n+# error \"Feature-test macro for tuple-like is missing\"\n+#elif __cplusplus > 202302L\n+# if __cpp_lib_tuple_like < 202311L\n+# error \"Feature-test macro for tuple-like has wrong value\"\n+# endif\n+#else\n+# if __cpp_lib_tuple_like < 202207L\n+# error \"Feature-test macro for tuple-like has wrong value\"\n+# endif\n+#endif\n+\ndiff --git a/libstdc++-v3/testsuite/26_numerics/complex/tuple_like.cc b/libstdc++-v3/testsuite/26_numerics/complex/tuple_like.cc\nnew file mode 100644\nindex 000000000000..7d8d2ee99ce7\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/26_numerics/complex/tuple_like.cc\n@@ -0,0 +1,179 @@\n+// { dg-do compile { target c++26 } }\n+\n+#include <complex>\n+#include <ranges>\n+#include <string>\n+#include <type_traits>\n+#include <tuple>\n+#include <utility>\n+\n+#include <testsuite_hooks.h>\n+\n+template <typename T>\n+constexpr\n+void\n+test_sanity()\n+{\n+ using C = std::complex<T>;\n+\n+ static_assert(std::tuple_size_v<C> == 2);\n+ static_assert(std::is_same_v<std::tuple_element_t<0, C>, T>);\n+ static_assert(std::is_same_v<std::tuple_element_t<1, C>, T>);\n+\n+ static_assert(std::is_same_v<decltype(get<0>(std::declval<C&>())), T&>);\n+ static_assert(std::is_same_v<decltype(get<1>(std::declval<C&>())), T&>);\n+ static_assert(std::is_same_v<decltype(get<0>(std::declval<const C&>())), const T&>);\n+ static_assert(std::is_same_v<decltype(get<1>(std::declval<const C&>())), const T&>);\n+ static_assert(std::is_same_v<decltype(get<0>(std::declval<C>())), T&&>);\n+ static_assert(std::is_same_v<decltype(get<1>(std::declval<C>())), T&&>);\n+ static_assert(std::is_same_v<decltype(get<0>(std::declval<const C>())), const T&&>);\n+ static_assert(std::is_same_v<decltype(get<1>(std::declval<const C>())), const T&&>);\n+}\n+\n+template <typename T>\n+constexpr\n+void\n+test_get()\n+{\n+ using C = std::complex<T>;\n+\n+ C cpx(T(1), T(2));\n+ VERIFY(std::get<0>(cpx) == T(1));\n+ VERIFY(std::get<1>(cpx) == T(2));\n+\n+ const C cpx2(T(3), T(4));\n+ VERIFY(std::get<0>(cpx2) == T(3));\n+ VERIFY(std::get<1>(cpx2) == T(4));\n+\n+ struct derived : public C { using C::C; };\n+ derived cpx3(T(5), T(6));\n+ VERIFY(std::get<0>(cpx3) == T(5));\n+ VERIFY(std::get<1>(cpx3) == T(6));\n+}\n+\n+template <typename T>\n+constexpr\n+void\n+test_structured_binding()\n+{\n+ using C = std::complex<T>;\n+ C cpx(T(1), T(2));\n+\n+ auto& [r, i] = cpx;\n+ VERIFY(r == T(1));\n+ VERIFY(i == T(2));\n+\n+ r = T(3);\n+ VERIFY(cpx.real() == T(3));\n+ VERIFY(cpx.imag() == T(2));\n+\n+ i = T(4);\n+ VERIFY(cpx.real() == T(3));\n+ VERIFY(cpx.imag() == T(4));\n+\n+ const C cpx2(T(5), T(6));\n+ auto& [r2, i2] = cpx2;\n+ VERIFY(r2 == T(5));\n+ VERIFY(i2 == T(6));\n+}\n+\n+template <typename T>\n+constexpr\n+void\n+test_tuple_cat()\n+{\n+ std::complex<T> cpx(T(1), T(2));\n+ std::pair<int, std::string> p(42, \"hello\");\n+\n+ auto r = std::tuple_cat(cpx, p, cpx);\n+ static_assert(std::is_same_v<decltype(r), std::tuple<T, T, int, std::string, T, T>>);\n+ VERIFY(std::get<0>(r) == T(1));\n+ VERIFY(std::get<1>(r) == T(2));\n+ VERIFY(std::get<2>(r) == 42);\n+ VERIFY(std::get<3>(r) == \"hello\");\n+ VERIFY(std::get<4>(r) == T(1));\n+ VERIFY(std::get<5>(r) == T(2));\n+}\n+\n+template <typename T>\n+constexpr\n+void\n+test_element_view()\n+{\n+ std::complex<T> array[5] = {\n+ { T(0), T(1) },\n+ { T(2), T(3) },\n+ { T(4), T(5) },\n+ { T(6), T(7) },\n+ { T(8), T(9) }\n+ };\n+\n+ T real_reduction = std::ranges::fold_left(array | std::views::keys, {}, std::plus{});\n+ VERIFY(real_reduction == T(20));\n+\n+ T imag_reduction = std::ranges::fold_left(array | std::views::values, {}, std::plus{});\n+ VERIFY(imag_reduction == T(25));\n+}\n+\n+template <typename T>\n+constexpr\n+void\n+test_apply()\n+{\n+ std::complex<T> cpx(T(1), T(2));\n+\n+ auto f = [](T a, T b) { return a + b; };\n+ auto result = std::apply(f, cpx);\n+\n+ VERIFY(result == T(3));\n+}\n+\n+template <typename T>\n+constexpr\n+bool\n+all_tests()\n+{\n+ test_sanity<T>();\n+ test_structured_binding<T>();\n+ test_tuple_cat<T>();\n+ test_element_view<T>();\n+ test_apply<T>();\n+ test_get<T>();\n+ return true;\n+}\n+\n+#define TEST(T) \\\n+ static_assert(all_tests<T>()); \\\n+ template T& std::get<0, T>(std::complex<T>&); \\\n+ template T& std::get<1, T>(std::complex<T>&); \\\n+ template T&& std::get<0, T>(std::complex<T>&&); \\\n+ template T&& std::get<1, T>(std::complex<T>&&); \\\n+ template const T& std::get<0, T>(const std::complex<T>&); \\\n+ template const T& std::get<1, T>(const std::complex<T>&); \\\n+ template const T&& std::get<0, T>(const std::complex<T>&&); \\\n+ template const T&& std::get<1, T>(const std::complex<T>&&); \\\n+\n+TEST(float)\n+TEST(double)\n+TEST(long double)\n+\n+#ifdef __STDCPP_FLOAT16_T__\n+TEST(_Float16)\n+#endif\n+#ifdef __STDCPP_FLOAT32_T__\n+TEST(_Float32)\n+#endif\n+#ifdef __STDCPP_FLOAT64_T__\n+TEST(_Float64)\n+#endif\n+#ifdef __STDCPP_FLOAT128_T__\n+TEST(_Float128)\n+#endif\n+#ifdef __STDCPP_BFLOAT16_T__\n+TEST(__gnu_cxx::__bfloat16_t)\n+#endif\n+\n+TEST(char)\n+TEST(int)\n+TEST(unsigned int)\n+TEST(size_t)\n", "prefixes": [ "v1", "1/1" ] }