aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2025-02-27 22:47:27 +0100
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2025-03-06 12:24:47 +0100
commitde231924b73bc120bf2b7ada4eeccd884c249ee1 (patch)
treecadf4d023406d46b4bb1d55b2fef8d1f0d3595ee /libstdc++-v3/testsuite
parente836d80374aa03a5ea5bd6cca00d826020c461da (diff)
downloadgcc-de231924b73bc120bf2b7ada4eeccd884c249ee1.zip
gcc-de231924b73bc120bf2b7ada4eeccd884c249ee1.tar.gz
gcc-de231924b73bc120bf2b7ada4eeccd884c249ee1.tar.bz2
libstdc++: implement tuple protocol for std::complex (P2819R2)
This commit implements P2819R2 for C++26, making std::complex destructurable and tuple-like (see [complex.tuple]). std::get needs to get forward declared in stl_pair.h (following the existing precedent for the implementation of P2165R4, cf. r14-8710-g65b4cba9d6a9ff), and implemented in <complex>. Also, std::get(complex<T>) needs to return *references* to the real and imaginary parts of a std::complex object, honoring the value category and constness of the argument. In principle a straightforward task, it gets a bit convoluted by the fact that: 1) std::complex does not have existing getters that one can use for this (real() and imag() return values, not references); 2) there are specializations for language/extended floating-point types, which requires some duplication -- need to amend the primary and all the specializations; 3) these specializations use a `__complex__ T`, but the primary template uses two non-static data members, making generic code harder to write. The implementation choice used here is to add the overloads of std::get for complex as declared in [complex.tuple]. In turn they dispatch to a newly added getter that extracts references to the real/imaginary parts of a complex<T>. This getter is private API, and the implementation depends on whether it's the primary (bind the data member) or a specialization (use the GCC language extensions for __complex__). To avoid duplication and minimize template instantiations, the getter uses C++23's deducing this (this avoids const overloads). The value category is dealt with by the std::get overloads. Add a test that covers the aspects of the tuple protocol, as well as the tuple-like interface. While at it, add a test for the existing tuple-like feature-testing macro. PR libstdc++/113310 libstdc++-v3/ChangeLog: * include/bits/stl_pair.h (get): Forward-declare std::get for std::complex. * include/bits/version.def (tuple_like): Bump the value of the feature-testing macro in C++26. * include/bits/version.h: Regenerate. * include/std/complex: Implement the tuple protocol for std::complex. (tuple_size): Specialize for std::complex. (tuple_element): Ditto. (__is_tuple_like_v): Ditto. (complex): Add a private getter to obtain references to the real and the imaginary part, on the primary class template and on its specializations. (get): Add overloads of std::get for std::complex. * testsuite/20_util/tuple/tuple_like_ftm.cc: New test. * testsuite/26_numerics/complex/tuple_like.cc: New test.
Diffstat (limited to 'libstdc++-v3/testsuite')
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/tuple_like_ftm.cc17
-rw-r--r--libstdc++-v3/testsuite/26_numerics/complex/tuple_like.cc179
2 files changed, 196 insertions, 0 deletions
diff --git a/libstdc++-v3/testsuite/20_util/tuple/tuple_like_ftm.cc b/libstdc++-v3/testsuite/20_util/tuple/tuple_like_ftm.cc
new file mode 100644
index 0000000..d7399b5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/tuple_like_ftm.cc
@@ -0,0 +1,17 @@
+// { dg-do preprocess { target c++23 } }
+// { dg-add-options no_pch }
+
+#include <utility>
+
+#if !defined(__cpp_lib_tuple_like)
+# error "Feature-test macro for tuple-like is missing"
+#elif __cplusplus > 202302L
+# if __cpp_lib_tuple_like < 202311L
+# error "Feature-test macro for tuple-like has wrong value"
+# endif
+#else
+# if __cpp_lib_tuple_like < 202207L
+# error "Feature-test macro for tuple-like has wrong value"
+# endif
+#endif
+
diff --git a/libstdc++-v3/testsuite/26_numerics/complex/tuple_like.cc b/libstdc++-v3/testsuite/26_numerics/complex/tuple_like.cc
new file mode 100644
index 0000000..7d8d2ee
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/complex/tuple_like.cc
@@ -0,0 +1,179 @@
+// { dg-do compile { target c++26 } }
+
+#include <complex>
+#include <ranges>
+#include <string>
+#include <type_traits>
+#include <tuple>
+#include <utility>
+
+#include <testsuite_hooks.h>
+
+template <typename T>
+constexpr
+void
+test_sanity()
+{
+ using C = std::complex<T>;
+
+ static_assert(std::tuple_size_v<C> == 2);
+ static_assert(std::is_same_v<std::tuple_element_t<0, C>, T>);
+ static_assert(std::is_same_v<std::tuple_element_t<1, C>, T>);
+
+ static_assert(std::is_same_v<decltype(get<0>(std::declval<C&>())), T&>);
+ static_assert(std::is_same_v<decltype(get<1>(std::declval<C&>())), T&>);
+ static_assert(std::is_same_v<decltype(get<0>(std::declval<const C&>())), const T&>);
+ static_assert(std::is_same_v<decltype(get<1>(std::declval<const C&>())), const T&>);
+ static_assert(std::is_same_v<decltype(get<0>(std::declval<C>())), T&&>);
+ static_assert(std::is_same_v<decltype(get<1>(std::declval<C>())), T&&>);
+ static_assert(std::is_same_v<decltype(get<0>(std::declval<const C>())), const T&&>);
+ static_assert(std::is_same_v<decltype(get<1>(std::declval<const C>())), const T&&>);
+}
+
+template <typename T>
+constexpr
+void
+test_get()
+{
+ using C = std::complex<T>;
+
+ C cpx(T(1), T(2));
+ VERIFY(std::get<0>(cpx) == T(1));
+ VERIFY(std::get<1>(cpx) == T(2));
+
+ const C cpx2(T(3), T(4));
+ VERIFY(std::get<0>(cpx2) == T(3));
+ VERIFY(std::get<1>(cpx2) == T(4));
+
+ struct derived : public C { using C::C; };
+ derived cpx3(T(5), T(6));
+ VERIFY(std::get<0>(cpx3) == T(5));
+ VERIFY(std::get<1>(cpx3) == T(6));
+}
+
+template <typename T>
+constexpr
+void
+test_structured_binding()
+{
+ using C = std::complex<T>;
+ C cpx(T(1), T(2));
+
+ auto& [r, i] = cpx;
+ VERIFY(r == T(1));
+ VERIFY(i == T(2));
+
+ r = T(3);
+ VERIFY(cpx.real() == T(3));
+ VERIFY(cpx.imag() == T(2));
+
+ i = T(4);
+ VERIFY(cpx.real() == T(3));
+ VERIFY(cpx.imag() == T(4));
+
+ const C cpx2(T(5), T(6));
+ auto& [r2, i2] = cpx2;
+ VERIFY(r2 == T(5));
+ VERIFY(i2 == T(6));
+}
+
+template <typename T>
+constexpr
+void
+test_tuple_cat()
+{
+ std::complex<T> cpx(T(1), T(2));
+ std::pair<int, std::string> p(42, "hello");
+
+ auto r = std::tuple_cat(cpx, p, cpx);
+ static_assert(std::is_same_v<decltype(r), std::tuple<T, T, int, std::string, T, T>>);
+ VERIFY(std::get<0>(r) == T(1));
+ VERIFY(std::get<1>(r) == T(2));
+ VERIFY(std::get<2>(r) == 42);
+ VERIFY(std::get<3>(r) == "hello");
+ VERIFY(std::get<4>(r) == T(1));
+ VERIFY(std::get<5>(r) == T(2));
+}
+
+template <typename T>
+constexpr
+void
+test_element_view()
+{
+ std::complex<T> array[5] = {
+ { T(0), T(1) },
+ { T(2), T(3) },
+ { T(4), T(5) },
+ { T(6), T(7) },
+ { T(8), T(9) }
+ };
+
+ T real_reduction = std::ranges::fold_left(array | std::views::keys, {}, std::plus{});
+ VERIFY(real_reduction == T(20));
+
+ T imag_reduction = std::ranges::fold_left(array | std::views::values, {}, std::plus{});
+ VERIFY(imag_reduction == T(25));
+}
+
+template <typename T>
+constexpr
+void
+test_apply()
+{
+ std::complex<T> cpx(T(1), T(2));
+
+ auto f = [](T a, T b) { return a + b; };
+ auto result = std::apply(f, cpx);
+
+ VERIFY(result == T(3));
+}
+
+template <typename T>
+constexpr
+bool
+all_tests()
+{
+ test_sanity<T>();
+ test_structured_binding<T>();
+ test_tuple_cat<T>();
+ test_element_view<T>();
+ test_apply<T>();
+ test_get<T>();
+ return true;
+}
+
+#define TEST(T) \
+ static_assert(all_tests<T>()); \
+ template T& std::get<0, T>(std::complex<T>&); \
+ template T& std::get<1, T>(std::complex<T>&); \
+ template T&& std::get<0, T>(std::complex<T>&&); \
+ template T&& std::get<1, T>(std::complex<T>&&); \
+ template const T& std::get<0, T>(const std::complex<T>&); \
+ template const T& std::get<1, T>(const std::complex<T>&); \
+ template const T&& std::get<0, T>(const std::complex<T>&&); \
+ template const T&& std::get<1, T>(const std::complex<T>&&); \
+
+TEST(float)
+TEST(double)
+TEST(long double)
+
+#ifdef __STDCPP_FLOAT16_T__
+TEST(_Float16)
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+TEST(_Float32)
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+TEST(_Float64)
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+TEST(_Float128)
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+TEST(__gnu_cxx::__bfloat16_t)
+#endif
+
+TEST(char)
+TEST(int)
+TEST(unsigned int)
+TEST(size_t)