| // This file is part of Eigen, a lightweight C++ template library |
| // for linear algebra. |
| // |
| // Copyright (C) 2026 Pavel Guzenfeld |
| // |
| // This Source Code Form is subject to the terms of the Mozilla |
| // Public License v. 2.0. If a copy of the MPL was not distributed |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| |
| #include "main.h" |
| |
| #if EIGEN_MAX_CPP_VER >= 17 && EIGEN_COMP_CXXVER >= 17 |
| |
| template <typename Scalar> |
| void check_vector_bindings() { |
| // Vector2 |
| { |
| Matrix<Scalar, 2, 1> v; |
| v << Scalar(1), Scalar(2); |
| auto [x, y] = v; |
| VERIFY_IS_EQUAL(x, Scalar(1)); |
| VERIFY_IS_EQUAL(y, Scalar(2)); |
| } |
| |
| // Vector3 |
| { |
| Matrix<Scalar, 3, 1> v; |
| v << Scalar(3), Scalar(4), Scalar(5); |
| auto [x, y, z] = v; |
| VERIFY_IS_EQUAL(x, Scalar(3)); |
| VERIFY_IS_EQUAL(y, Scalar(4)); |
| VERIFY_IS_EQUAL(z, Scalar(5)); |
| } |
| |
| // Vector4 |
| { |
| Matrix<Scalar, 4, 1> v; |
| v << Scalar(6), Scalar(7), Scalar(8), Scalar(9); |
| auto [a, b, c, d] = v; |
| VERIFY_IS_EQUAL(a, Scalar(6)); |
| VERIFY_IS_EQUAL(b, Scalar(7)); |
| VERIFY_IS_EQUAL(c, Scalar(8)); |
| VERIFY_IS_EQUAL(d, Scalar(9)); |
| } |
| |
| // 1x1 matrix (scalar-like) |
| { |
| Matrix<Scalar, 1, 1> s; |
| s << Scalar(42); |
| auto [val] = s; |
| VERIFY_IS_EQUAL(val, Scalar(42)); |
| } |
| |
| // RowVector |
| { |
| Matrix<Scalar, 1, 3> rv; |
| rv << Scalar(10), Scalar(20), Scalar(30); |
| auto [a, b, c] = rv; |
| VERIFY_IS_EQUAL(a, Scalar(10)); |
| VERIFY_IS_EQUAL(b, Scalar(20)); |
| VERIFY_IS_EQUAL(c, Scalar(30)); |
| } |
| } |
| |
| template <typename Scalar> |
| void check_array_bindings() { |
| // Array3 |
| { |
| Array<Scalar, 3, 1> a; |
| a << Scalar(100), Scalar(200), Scalar(300); |
| auto [x, y, z] = a; |
| VERIFY_IS_EQUAL(x, Scalar(100)); |
| VERIFY_IS_EQUAL(y, Scalar(200)); |
| VERIFY_IS_EQUAL(z, Scalar(300)); |
| } |
| |
| // Array2 |
| { |
| Array<Scalar, 2, 1> a; |
| a << Scalar(10), Scalar(20); |
| auto [x, y] = a; |
| VERIFY_IS_EQUAL(x, Scalar(10)); |
| VERIFY_IS_EQUAL(y, Scalar(20)); |
| } |
| } |
| |
| template <typename Scalar> |
| void check_reference_bindings() { |
| // Mutable reference binding |
| { |
| Matrix<Scalar, 3, 1> v; |
| v << Scalar(1), Scalar(2), Scalar(3); |
| auto& [x, y, z] = v; |
| x = Scalar(10); |
| y = Scalar(20); |
| z = Scalar(30); |
| VERIFY_IS_EQUAL(v(0), Scalar(10)); |
| VERIFY_IS_EQUAL(v(1), Scalar(20)); |
| VERIFY_IS_EQUAL(v(2), Scalar(30)); |
| } |
| |
| // Const reference binding |
| { |
| const Matrix<Scalar, 3, 1> v(Scalar(4), Scalar(5), Scalar(6)); |
| const auto& [x, y, z] = v; |
| VERIFY_IS_EQUAL(x, Scalar(4)); |
| VERIFY_IS_EQUAL(y, Scalar(5)); |
| VERIFY_IS_EQUAL(z, Scalar(6)); |
| } |
| |
| // Array mutable reference binding |
| { |
| Array<Scalar, 2, 1> a; |
| a << Scalar(7), Scalar(8); |
| auto& [x, y] = a; |
| x = Scalar(70); |
| VERIFY_IS_EQUAL(a(0), Scalar(70)); |
| VERIFY_IS_EQUAL(a(1), Scalar(8)); |
| } |
| } |
| |
| template <typename Scalar> |
| void check_matrix_bindings() { |
| // 2x2 matrix (column-major order) |
| { |
| Matrix<Scalar, 2, 2> m; |
| m << Scalar(1), Scalar(2), Scalar(3), Scalar(4); |
| auto [m00, m10, m01, m11] = m; |
| // Column-major: (0,0), (1,0), (0,1), (1,1) |
| VERIFY_IS_EQUAL(m00, Scalar(1)); |
| VERIFY_IS_EQUAL(m10, Scalar(3)); |
| VERIFY_IS_EQUAL(m01, Scalar(2)); |
| VERIFY_IS_EQUAL(m11, Scalar(4)); |
| } |
| } |
| |
| template <typename Scalar> |
| void check_storage_order_semantics() { |
| // Row vectors are forced to RowMajor by Eigen (a 1xN can't meaningfully be |
| // column-major). Ensure decomposition still matches the single-row layout. |
| { |
| Matrix<Scalar, 1, 3> rv; |
| rv << Scalar(1), Scalar(2), Scalar(3); |
| auto [a, b, c] = rv; |
| VERIFY_IS_EQUAL(a, Scalar(1)); |
| VERIFY_IS_EQUAL(b, Scalar(2)); |
| VERIFY_IS_EQUAL(c, Scalar(3)); |
| } |
| // Nx1 column vectors are ColMajor regardless and decompose top-to-bottom. |
| { |
| Matrix<Scalar, 3, 1> cv; |
| cv << Scalar(4), Scalar(5), Scalar(6); |
| auto [a, b, c] = cv; |
| VERIFY_IS_EQUAL(a, Scalar(4)); |
| VERIFY_IS_EQUAL(b, Scalar(5)); |
| VERIFY_IS_EQUAL(c, Scalar(6)); |
| } |
| // 2D ColMajor matrix decomposes in column-major order: (0,0),(1,0),(0,1),(1,1). |
| // 2D RowMajor is rejected via static_assert — see failtest/structured_bindings_rowmajor.cpp. |
| { |
| Matrix<Scalar, 2, 2, ColMajor> m; |
| m << Scalar(1), Scalar(2), Scalar(3), Scalar(4); |
| auto [m00, m10, m01, m11] = m; |
| VERIFY_IS_EQUAL(m00, Scalar(1)); |
| VERIFY_IS_EQUAL(m10, Scalar(3)); |
| VERIFY_IS_EQUAL(m01, Scalar(2)); |
| VERIFY_IS_EQUAL(m11, Scalar(4)); |
| } |
| } |
| |
| void check_tuple_size() { |
| STATIC_CHECK((std::tuple_size<Vector2d>::value == 2)); |
| STATIC_CHECK((std::tuple_size<Vector3f>::value == 3)); |
| STATIC_CHECK((std::tuple_size<Vector4i>::value == 4)); |
| STATIC_CHECK((std::tuple_size<Matrix2d>::value == 4)); |
| STATIC_CHECK((std::tuple_size<Matrix3f>::value == 9)); |
| STATIC_CHECK((std::tuple_size<Array3i>::value == 3)); |
| STATIC_CHECK((std::tuple_size<Array<double, 2, 1>>::value == 2)); |
| STATIC_CHECK((std::tuple_size<Matrix<float, 1, 1>>::value == 1)); |
| STATIC_CHECK((std::tuple_size<RowVector3d>::value == 3)); |
| } |
| |
| void check_tuple_element() { |
| STATIC_CHECK((std::is_same<std::tuple_element_t<0, Vector3d>, double>::value)); |
| STATIC_CHECK((std::is_same<std::tuple_element_t<1, Vector3f>, float>::value)); |
| STATIC_CHECK((std::is_same<std::tuple_element_t<2, Vector4i>, int>::value)); |
| STATIC_CHECK((std::is_same<std::tuple_element_t<0, Array3i>, int>::value)); |
| } |
| |
| EIGEN_DECLARE_TEST(structured_bindings) { |
| CALL_SUBTEST_1(check_vector_bindings<double>()); |
| CALL_SUBTEST_1(check_vector_bindings<float>()); |
| CALL_SUBTEST_1(check_vector_bindings<int>()); |
| CALL_SUBTEST_2(check_array_bindings<double>()); |
| CALL_SUBTEST_2(check_array_bindings<int>()); |
| CALL_SUBTEST_3(check_reference_bindings<double>()); |
| CALL_SUBTEST_3(check_reference_bindings<float>()); |
| CALL_SUBTEST_4(check_matrix_bindings<double>()); |
| CALL_SUBTEST_4(check_matrix_bindings<int>()); |
| CALL_SUBTEST_5(check_tuple_size()); |
| CALL_SUBTEST_5(check_tuple_element()); |
| CALL_SUBTEST_6(check_storage_order_semantics<double>()); |
| CALL_SUBTEST_6(check_storage_order_semantics<int>()); |
| } |
| |
| #else |
| |
| EIGEN_DECLARE_TEST(structured_bindings) { |
| // Structured bindings require C++17. |
| VERIFY(true); |
| } |
| |
| #endif |