| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // Copyright (C) 2022 Alex Richardson <alexrichardson@google.com> | |
| // | |
| // 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 | |
| #define EIGEN_TESTING_CONSTEXPR | |
| #include "main.h" | |
| template <typename Scalar, int Rows> | |
| struct ConstexprTest { | |
| constexpr ConstexprTest(const Matrix<Scalar, Rows, Rows>& B) { A = B; } | |
| Matrix<Scalar, Rows, Rows> A; | |
| }; | |
| template <typename Scalar, int Rows> | |
| struct ConstexprArrayTest { | |
| constexpr ConstexprArrayTest(const Array<Scalar, Rows, Rows>& B) { A = B; } | |
| Array<Scalar, Rows, Rows> A; | |
| }; | |
| template <typename Scalar, int Rows> | |
| struct ConstexprArrayMoveTest { | |
| constexpr ConstexprArrayMoveTest(Array<Scalar, Rows, Rows> B) { A = std::move(B); } | |
| Array<Scalar, Rows, Rows> A; | |
| }; | |
| EIGEN_DECLARE_TEST(constexpr) { | |
| // Clang accepts (some of) this code when using C++14/C++17, but GCC does not like | |
| // the fact that `T array[Size]` inside Eigen::internal::plain_array is not initialized | |
| // until after the constructor returns: | |
| // error: member ‘Eigen::internal::plain_array<int, 9, 0, 0>::array’ must be initialized by mem-initializer in | |
| // ‘constexpr’ constructor | |
| #if __cpp_constexpr >= 201907L | |
| constexpr Matrix3i mat({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); | |
| VERIFY_IS_EQUAL(mat.size(), 9); | |
| static_assert(mat(0, 0) == 1); | |
| static_assert(mat(0) == 1); | |
| static_assert(mat.coeff(0, 1) == 2); | |
| constexpr Array33i arr({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); | |
| static_assert(arr(0, 0) == 1); | |
| static_assert(arr(0) == 1); | |
| VERIFY_IS_EQUAL(arr.size(), 9); | |
| static_assert(arr.coeff(0, 1) == 2); | |
| constexpr RowVector3i vec{{1, 2, 3}}; | |
| static_assert(vec(0, 0) == 1); | |
| static_assert(vec[0] == 1); | |
| VERIFY_IS_EQUAL(vec.size(), 3); | |
| static_assert(vec.coeff(0, 1) == 2); | |
| // Check assignment. A wrapper struct is used to avoid copy elision. | |
| constexpr ConstexprTest<double, 2> obj1(Matrix2d({{1, 2}, {3, 4}})); | |
| VERIFY_IS_EQUAL(obj1.A.size(), 4); | |
| static_assert(obj1.A(0, 0) == 1); | |
| static_assert(obj1.A(0) == 1); | |
| static_assert(obj1.A.coeff(0, 1) == 2); | |
| constexpr ConstexprTest<double, 3> obj2(Matrix3d({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}})); | |
| VERIFY_IS_EQUAL(obj2.A.size(), 9); | |
| static_assert(obj2.A(0, 0) == 1); | |
| static_assert(obj2.A(0) == 1); | |
| static_assert(obj2.A.coeff(0, 1) == 2); | |
| constexpr ConstexprArrayTest<double, 2> arr_obj1(Array22d({{1, 2}, {3, 4}})); | |
| VERIFY_IS_EQUAL(arr_obj1.A.size(), 4); | |
| static_assert(arr_obj1.A(0, 0) == 1); | |
| static_assert(arr_obj1.A(0) == 1); | |
| static_assert(arr_obj1.A.coeff(0, 1) == 2); | |
| constexpr ConstexprArrayMoveTest<double, 2> arr_move_obj(Array22d({{1, 2}, {3, 4}})); | |
| static_assert(arr_move_obj.A(0, 0) == 1); | |
| static_assert(arr_move_obj.A.coeff(0, 1) == 2); | |
| // Also check dynamic size arrays/matrices with fixed-size storage (currently | |
| // only works if all elements are initialized, since otherwise the compiler | |
| // complains about uninitialized trailing elements. | |
| constexpr Matrix<int, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> dyn_mat({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); | |
| VERIFY_IS_EQUAL(dyn_mat.size(), 9); | |
| static_assert(dyn_mat(0, 0) == 1); | |
| static_assert(dyn_mat.coeff(0, 1) == 2); | |
| constexpr Array<int, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> dyn_arr({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); | |
| static_assert(dyn_arr(0, 0) == 1); | |
| static_assert(dyn_arr(0) == 1); | |
| VERIFY_IS_EQUAL(dyn_arr.size(), 9); | |
| static_assert(dyn_arr.coeff(0, 1) == 2); | |
| // Test matrix addition. | |
| constexpr Matrix3i mat_a({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); | |
| constexpr Matrix3i mat_b({{9, 8, 7}, {6, 5, 4}, {3, 2, 1}}); | |
| constexpr Matrix3i mat_sum = mat_a + mat_b; | |
| static_assert(mat_sum(0, 0) == 10); | |
| static_assert(mat_sum(1, 1) == 10); | |
| static_assert(mat_sum(2, 2) == 10); | |
| // Test matrix subtraction. | |
| constexpr Matrix3i mat_diff = mat_a - mat_b; | |
| static_assert(mat_diff(0, 0) == -8); | |
| static_assert(mat_diff(1, 1) == 0); | |
| static_assert(mat_diff(2, 2) == 8); | |
| // Test scalar multiplication. | |
| constexpr Matrix3i mat_scaled = mat_a * 2; | |
| static_assert(mat_scaled(0, 0) == 2); | |
| static_assert(mat_scaled(1, 1) == 10); | |
| static_assert(mat_scaled(2, 2) == 18); | |
| #endif // __cpp_constexpr >= 201907L | |
| } | |
| // Check that we can use the std::initializer_list constructor for constexpr variables. | |
| #if __cpp_constexpr >= 201907L | |
| // EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT() will fail constexpr evaluation unless | |
| // we have std::is_constant_evaluated(). | |
| constexpr Matrix<int, 2, 2> global_mat({{1, 2}, {3, 4}}); | |
| EIGEN_DECLARE_TEST(constexpr_global) { | |
| VERIFY_IS_EQUAL(global_mat.size(), 4); | |
| static_assert(global_mat(0, 0) == 1); | |
| static_assert(global_mat(0) == 1); | |
| static_assert(global_mat.coeff(0, 0) == 1); | |
| } | |
| #endif // __cpp_constexpr >= 201907L | |
| // Check that preprocessor correctly parses and expands EIGEN_IF_CONSTEXPR arguments containing commas | |
| EIGEN_DECLARE_TEST(constexpr_if) { | |
| int true_branch_executed = 0; | |
| int false_branch_executed = 0; | |
| EIGEN_IF_CONSTEXPR (std::is_same<int, int>::value) { | |
| true_branch_executed++; | |
| } else { | |
| false_branch_executed++; | |
| } | |
| EIGEN_IF_CONSTEXPR (std::is_same<int, float>::value) { | |
| true_branch_executed++; | |
| } else { | |
| false_branch_executed++; | |
| } | |
| VERIFY_IS_EQUAL(true_branch_executed, 1); | |
| VERIFY_IS_EQUAL(false_branch_executed, 1); | |
| } |