// 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/. // SPDX-License-Identifier: MPL-2.0 #include "main.h" #if EIGEN_MAX_CPP_VER >= 17 && EIGEN_COMP_CXXVER >= 17 template void check_vector_bindings() { // Vector2 { Matrix v; v << Scalar(1), Scalar(2); auto [x, y] = v; VERIFY_IS_EQUAL(x, Scalar(1)); VERIFY_IS_EQUAL(y, Scalar(2)); } // Vector3 { Matrix 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 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 s; s << Scalar(42); auto [val] = s; VERIFY_IS_EQUAL(val, Scalar(42)); } // RowVector { Matrix 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 void check_array_bindings() { // Array3 { Array 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 a; a << Scalar(10), Scalar(20); auto [x, y] = a; VERIFY_IS_EQUAL(x, Scalar(10)); VERIFY_IS_EQUAL(y, Scalar(20)); } } template void check_reference_bindings() { // Mutable reference binding { Matrix 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 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 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 void check_matrix_bindings() { // 2x2 matrix (column-major order) { Matrix 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 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 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 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 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::value == 2)); STATIC_CHECK((std::tuple_size::value == 3)); STATIC_CHECK((std::tuple_size::value == 4)); STATIC_CHECK((std::tuple_size::value == 4)); STATIC_CHECK((std::tuple_size::value == 9)); STATIC_CHECK((std::tuple_size::value == 3)); STATIC_CHECK((std::tuple_size>::value == 2)); STATIC_CHECK((std::tuple_size>::value == 1)); STATIC_CHECK((std::tuple_size::value == 3)); } void check_tuple_element() { STATIC_CHECK((std::is_same, double>::value)); STATIC_CHECK((std::is_same, float>::value)); STATIC_CHECK((std::is_same, int>::value)); STATIC_CHECK((std::is_same, int>::value)); } // Emulates generic tuple-like detection as done by fmt's range formatter // (issue #3103): probing tuple_size::value in a SFINAE context must be a // substitution failure for dynamic-size types, not a hard error. template struct is_tuple_like : std::false_type {}; template struct is_tuple_like::value)>> : std::true_type {}; template struct has_tuple_element0 : std::false_type {}; template struct has_tuple_element0::type>> : std::true_type {}; void check_sfinae_friendly_detection() { STATIC_CHECK((is_tuple_like::value)); STATIC_CHECK((is_tuple_like::value)); STATIC_CHECK((is_tuple_like::value)); STATIC_CHECK((!is_tuple_like::value)); STATIC_CHECK((!is_tuple_like::value)); STATIC_CHECK((!is_tuple_like::value)); STATIC_CHECK((!is_tuple_like>::value)); STATIC_CHECK((!is_tuple_like>::value)); STATIC_CHECK((has_tuple_element0::value)); STATIC_CHECK((has_tuple_element0::value)); STATIC_CHECK((!has_tuple_element0::value)); STATIC_CHECK((!has_tuple_element0::value)); } EIGEN_DECLARE_TEST(structured_bindings) { CALL_SUBTEST_1(check_vector_bindings()); CALL_SUBTEST_1(check_vector_bindings()); CALL_SUBTEST_1(check_vector_bindings()); CALL_SUBTEST_2(check_array_bindings()); CALL_SUBTEST_2(check_array_bindings()); CALL_SUBTEST_3(check_reference_bindings()); CALL_SUBTEST_3(check_reference_bindings()); CALL_SUBTEST_4(check_matrix_bindings()); CALL_SUBTEST_4(check_matrix_bindings()); CALL_SUBTEST_5(check_tuple_size()); CALL_SUBTEST_5(check_tuple_element()); CALL_SUBTEST_5(check_sfinae_friendly_detection()); CALL_SUBTEST_6(check_storage_order_semantics()); CALL_SUBTEST_6(check_storage_order_semantics()); } #else EIGEN_DECLARE_TEST(structured_bindings) { // Structured bindings require C++17. VERIFY(true); } #endif