Eigen  5.0.1
 
Loading...
Searching...
No Matches
StructuredBindings.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2026 Pavel Guzenfeld
5//
6// This Source Code Form is subject to the terms of the Mozilla
7// Public License v. 2.0. If a copy of the MPL was not distributed
8// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9// SPDX-License-Identifier: MPL-2.0
10
11#ifndef EIGEN_STRUCTURED_BINDINGS_H
12#define EIGEN_STRUCTURED_BINDINGS_H
13
14// IWYU pragma: private
15#include "./InternalHeaderCheck.h"
16
17#if EIGEN_MAX_CPP_VER >= 17 && EIGEN_COMP_CXXVER >= 17
18
19#include <tuple>
20#include <type_traits>
21
22// Structured bindings support for fixed-size Eigen vectors and matrices.
23//
24// Enables:
25// Eigen::Vector3d v(1, 2, 3);
26// auto [x, y, z] = v;
27//
28// Eigen::Array3i a(4, 5, 6);
29// auto& [a0, a1, a2] = a;
30//
31// Decomposition order follows storage order: column-major by default,
32// so Matrix2d decomposes as (0,0), (1,0), (0,1), (1,1). Only fixed-size
33// column-major Matrix and Array are tuple-like; Map, Ref, and fixed-size
34// Block intentionally do not participate.
35
36namespace Eigen {
37namespace internal {
38
39// Bases supplying value/type only for fixed-size shapes, leaving the std
40// specializations below memberless for dynamic sizes: generic tuple-like
41// detection probes std::tuple_size<T>::value in a SFINAE context (fmt's range
42// formatter, issue #3103) and needs a substitution failure, not a hard error.
43// An enable_if_t base-clause cannot replace this: base-class-specifier
44// substitution is not a SFINAE context.
45template <int Rows_, int Cols_, bool IsFixedSize_ = (Rows_ != Dynamic && Cols_ != Dynamic)>
46struct structured_binding_size {};
47
48template <int Rows_, int Cols_>
49struct structured_binding_size<Rows_, Cols_, true>
50 : std::integral_constant<size_t, static_cast<size_t>(Rows_) * static_cast<size_t>(Cols_)> {};
51
52// Note: uses Idx_ instead of I to avoid conflict with Eigen's test framework macro.
53template <size_t Idx_, typename Scalar_, int Rows_, int Cols_,
54 bool IsFixedSize_ = (Rows_ != Dynamic && Cols_ != Dynamic)>
55struct structured_binding_element {};
56
57template <size_t Idx_, typename Scalar_, int Rows_, int Cols_>
58struct structured_binding_element<Idx_, Scalar_, Rows_, Cols_, true> {
59 static_assert(Idx_ < static_cast<size_t>(Rows_) * static_cast<size_t>(Cols_), "Index out of range.");
60 using type = Scalar_;
61};
62
63} // namespace internal
64} // namespace Eigen
65
66namespace std {
67
68// std::tuple_size / std::tuple_element for Matrix.
69template <typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
70struct tuple_size<Eigen::Matrix<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>>
71 : Eigen::internal::structured_binding_size<Rows_, Cols_> {};
72
73template <size_t Idx_, typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
74struct tuple_element<Idx_, Eigen::Matrix<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>>
75 : Eigen::internal::structured_binding_element<Idx_, Scalar_, Rows_, Cols_> {};
76
77// std::tuple_size / std::tuple_element for Array.
78template <typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
79struct tuple_size<Eigen::Array<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>>
80 : Eigen::internal::structured_binding_size<Rows_, Cols_> {};
81
82template <size_t Idx_, typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
83struct tuple_element<Idx_, Eigen::Array<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>>
84 : Eigen::internal::structured_binding_element<Idx_, Scalar_, Rows_, Cols_> {};
85
86} // namespace std
87
88namespace Eigen {
89
90// Until the decomposition order for genuinely 2D RowMajor storage is agreed
91// upon, reject row-major matrices at the get<I> level. coeffRef(Index) is
92// linear in storage order, so permitting both orientations for 2D types would
93// silently flip the binding order between Matrix<T,R,C> and Matrix<T,R,C,RowMajor>.
94// Vector types (Rows==1 or Cols==1) are unaffected because storage order
95// does not change element order for a 1×N or N×1 shape — and Eigen forces
96// row-major on 1×N regardless, so we must allow it for row vectors.
97#define EIGEN_STRUCTURED_BINDINGS_ASSERT_COL_MAJOR(ROWS, COLS, OPTIONS) \
98 static_assert((ROWS <= 1 || COLS <= 1) || ((OPTIONS & RowMajor) == 0), \
99 "Structured bindings on 2D RowMajor Eigen matrices are disabled to prevent storage-order confusion.");
100
101// get<Idx_> free functions for Matrix.
102template <size_t Idx_, typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
103EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar_& get(
105 static_assert(Rows_ != Dynamic && Cols_ != Dynamic, "Structured bindings require fixed-size Eigen types.");
106 static_assert(Idx_ < static_cast<size_t>(Rows_ * Cols_), "Index out of range.");
107 EIGEN_STRUCTURED_BINDINGS_ASSERT_COL_MAJOR(Rows_, Cols_, Options_);
108 return m.coeffRef(static_cast<Index>(Idx_));
109}
110
111template <size_t Idx_, typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
112EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar_& get(
114 static_assert(Rows_ != Dynamic && Cols_ != Dynamic, "Structured bindings require fixed-size Eigen types.");
115 static_assert(Idx_ < static_cast<size_t>(Rows_ * Cols_), "Index out of range.");
116 EIGEN_STRUCTURED_BINDINGS_ASSERT_COL_MAJOR(Rows_, Cols_, Options_);
117 return m.coeffRef(static_cast<Index>(Idx_));
118}
119
120template <size_t Idx_, typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
121EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar_&& get(
123 static_assert(Rows_ != Dynamic && Cols_ != Dynamic, "Structured bindings require fixed-size Eigen types.");
124 static_assert(Idx_ < static_cast<size_t>(Rows_ * Cols_), "Index out of range.");
125 EIGEN_STRUCTURED_BINDINGS_ASSERT_COL_MAJOR(Rows_, Cols_, Options_);
126 return std::move(m.coeffRef(static_cast<Index>(Idx_)));
127}
128
129// get<Idx_> free functions for Array.
130template <size_t Idx_, typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
131EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar_& get(
133 static_assert(Rows_ != Dynamic && Cols_ != Dynamic, "Structured bindings require fixed-size Eigen types.");
134 static_assert(Idx_ < static_cast<size_t>(Rows_ * Cols_), "Index out of range.");
135 EIGEN_STRUCTURED_BINDINGS_ASSERT_COL_MAJOR(Rows_, Cols_, Options_);
136 return a.coeffRef(static_cast<Index>(Idx_));
137}
138
139template <size_t Idx_, typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
140EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar_& get(
142 static_assert(Rows_ != Dynamic && Cols_ != Dynamic, "Structured bindings require fixed-size Eigen types.");
143 static_assert(Idx_ < static_cast<size_t>(Rows_ * Cols_), "Index out of range.");
144 EIGEN_STRUCTURED_BINDINGS_ASSERT_COL_MAJOR(Rows_, Cols_, Options_);
145 return a.coeffRef(static_cast<Index>(Idx_));
146}
147
148template <size_t Idx_, typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
149EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar_&& get(
151 static_assert(Rows_ != Dynamic && Cols_ != Dynamic, "Structured bindings require fixed-size Eigen types.");
152 static_assert(Idx_ < static_cast<size_t>(Rows_ * Cols_), "Index out of range.");
153 EIGEN_STRUCTURED_BINDINGS_ASSERT_COL_MAJOR(Rows_, Cols_, Options_);
154 return std::move(a.coeffRef(static_cast<Index>(Idx_)));
155}
156
157} // namespace Eigen
158
159#endif // C++17
160
161#endif // EIGEN_STRUCTURED_BINDINGS_H
General-purpose arrays with easy API for coefficient-wise operations.
Definition Array.h:55
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188