Reputation: 819
I am trying to do a reduction based on eigen matrix.
#include <iostream>
#include <Eigen/Dense>
#include <type_traits>
template<typename T1, typename T2, int n1, int n2>
auto reduction(Eigen::Matrix<T1, n1, n2> &a1,
Eigen::Matrix<T2, n1, n2> &a2)
-> decltype(T1{}*T2{})
{
using BaseT3 =
typename std::remove_cv<typename std::remove_reference<decltype(T1{}*T2{})>::type>::type;
BaseT3 res = a1(0, 0)*a2(0, 0);
for (int i=0; i<n1; ++i)
for (int j=0; j<n2; ++j)
if (i+j)
res = res + a1(i, j)*a2(i, j);
return res;
}
int main()
{
Eigen::Matrix<double, 3, 3> m;
Eigen::Matrix<Eigen::Vector3d, 3, 3> n;
std::cout << reduction(m, n) << std::endl;
}
Basically, Im a trying to get sum_{i, j} a1[i, j] * a2[i, j]
where a1
and a2
are some eigen mathix but I get compilation errors. The error I get is
error: no match for ‘operator=’ (operand types are ‘BaseT3 {aka
Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<double>,
const Eigen::Matrix<double, 3, 1> >}’
and
‘const Eigen::CwiseBinaryOp<Eigen::internal::scalar_sum_op<double>,
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<double>,
const Eigen::Matrix<double, 3, 1> >,
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<double>,
const Eigen::Matrix<double, 3, 1> > >’)
res = res + a1(i, j)*a2(i, j);
^
If I am not mistaken, for the given main
, type BaseT3
should have been Eigen::Vector3d
. I also tried to static cast so the operator=
should not fail but I then get other errors.
This is c++11, I use Eigen3 and the compiler is g++ 5.4.1.
Upvotes: 2
Views: 482
Reputation: 275385
Eigen uses expression templates to optimize chains of operations.
So MatrixA*MatrixB is not a Matrix type, but rather an expression that says "when evaluated this will be the product of a MatrixA times a MatrixB".
The result is that A*B+C*D
doesn't create (at least as many) temporary matrixes, but instead when stored in an output matrix the results are "lazily" calculated directly into the output matrix.
Now, you are multipying elements. But one of your element types is in turn a matrix. And Eigen does expression template optimization of scalar times vector it turns out.
The type you want is std::decay_t<decltype((T1{}+T2{}).eval())>
(well the C++11 verbose version of that).
You could write a fancy SFINAE thing that checks if it can be evaluated, and if so does that. Or you can test for Eigen expression template types.
Upvotes: 1
Reputation: 10978
The decltype of T1 * T2 isn't what you expect here - Eigen heavily uses expression templates. The CWiseUnaryOp and CWiseBinaryOp types in your error are indicative of that. In other words, the result of "double * Vector3d" isn't what you'd expect (it's not a Vector3d, it's a cwisebinaryop).
See also: Writing functions taking Eigen Types.
In this specific case you may find a solution by creating partial specializations for Eigen base types for both the first and second parameters of your template function.
Upvotes: 4