Background
First started tinkering with extending initializer lists to use submatrices, and wanted to know how to generalize methods to work on mutable matrices (e.g., Matirix<...>
, Block<...>
).
(If you're curious, here's my post, but the attempts are either non-performant or failed.)
I reviewed some of this stuff:
- Eigen Documentation - C98 Hack - Remove
const
- Eigen Mailing List - Passing result of block() as non-const reference-to-matrix? - For C++03+, it mentions that you may use lvalue (
&
) and rvalue (&&
) references, but ends up re-implementing the method. - Eigen: type deduction in template specialization of base-class - Provides succinct usage of
decltype
for gettingDerived
specific toMatrixBase
at compile-time - A failure to instantiate function templates due to universal (forward) reference to a templated type - Provides reasing why
&&
would not be the templated perfect-forwarding case when your argument is not a directly-deduced template paramater (e.g.,MatrixBase<Derived>
vs.XprType
)
Working Example
Given all that, I cam up with (what I hope is) a relatively simple pattern:
Taking snippets from the example, this is the cleanest pattern-type I could see:
template<typename Derived>
Derived extract_mutable_derived_type(MatrixBase<Derived>&& value);
template<typename Derived>
Derived extract_mutable_derived_type(MatrixBase<Derived>& value);
template<typename T>
using mutable_matrix_derived_type = decltype(extract_mutable_derived_type(std::declval<T>()));
// Example using mutable_matrix_derived_type:
template<typename XprType,
typename Derived = mutable_matrix_derived_type<XprType>>
auto&& fill(XprType&& x) {
// cannot use decltype(x) on return type?
x.setConstant(1);
return std::forward<XprType>(x);
}
This can work on expressions such as:
MatrixXd A(2, 2);
fill(A); // lvalue, dynamic
Matrix3d B;
fill(B); // lvalue, static
MatrixXd C(3, 2);
fill(C.block(0, 0, 2, 2)); // rvalue, dynamic. Works as intended.
Vector3d y;
fill(y.head(2)); // rvalue, static
Main Question
Merging the lvalue and rvalue cases to work with things such as blocks seems a little hacky (less so than the C98 version), and not sure if a better mechanism has come up.
Is there a better mechanism to generically handle matrices (even blocks) when they are rvalues?
Or do you generally have to specialize yourself, and either (a) join them together as this example does, (b) specialize based on the rvalue case, or (c) specialize between generic MatrixBase<Derived>
(DenseBase<Derived>
) and Block<...>
?