Sooraj
Sooraj

Reputation: 615

Compilation Error Using template programming with Eigen C++ library

I downloaded Eigen (3) library and started using it. I wrote a template function and declared a local variable of 'template type' inside the function. I am getting the following compilation error.


$ g++ EigenTest.cpp

EigenTest.cpp: In instantiation of ‘void myFunc(Eigen::MatrixBase<Derived>&) [with Type1 = Eigen::Matrix<double, -1, -1>]’:
EigenTest.cpp:24:10:   required from here
EigenTest.cpp:16:26: error: conversion from ‘Eigen::DenseCoeffsBase<Eigen::Matrix<double, -1, -1>, 1>::Scalar {aka double}’ to non-scalar type ‘Eigen::Matrix<double, -1, -1>’ requested
   Type1 tmp = matrix(0, 0);

"EigenTest.cpp" is given below.


#include "Eigen/Dense"

#include <iostream>

template<typename Type1>
void myFunc(Eigen::MatrixBase<Type1>& matrix)
{
int i=matrix.rows();
Type1 tmp = matrix(0, 0);           // getting compiler error here
std::cout<<"tmp is ->"<<tmp<<std::endl;
}

int main()
{
Eigen::MatrixXd m(2,2);
m.setConstant(100); 
myFunc(m);
return 0;
}

I also tried using 'typename Type1 tmp = matrix(0, 0);'
This also didn't work!

How to fix this? In normal C++ template programming (without Eigen), I can define a local variable inside a template function as 'Type1 tmp;"

Upvotes: 1

Views: 7043

Answers (3)

ggael
ggael

Reputation: 29205

In Eigen::MatrixBase<Type1>, Type1 is not a scalar type but the type of the actual expression. In your example it will be MatrixXd but if myFunc is called on, e.g., m.block(...), then Type1 will be a Block<...>. To obtain the scalar type, you can use Type1::Scalar:

template<typename Type1>
void myFunc(Eigen::MatrixBase<Type1>& matrix)
{
  typename Type1::Scalar Scalar;
  Scalar tmp = matrix(0, 0);
}

And if you need a matrix type that is similar to Type1, use Type1::PlainObject, e.g.:

typename Type1::PlainObject mat = 2 * matrix * matrix.transpose();

Upvotes: 3

Grimm The Opiner
Grimm The Opiner

Reputation: 1806

It looks like MatrixBase uses the "CRTP" (see here), the template argument is actually the type deriving from it. Thus in your use of the method myFunc(), Type1 is actually representing Eigen::MatrixXd, and I think that you think Type1 is a double. So, this line:

Type1 tmp = matrix(0, 0);

In the documnetation for this library (see here) the typedef for MatrixXd is a matrix of doubles, so I guess the return from matrix(0, 0) is a double, and as tmp is of Type1 which is Eigen::MatrixXd, the one will not go into the other.

Scanning the docummentation I think it MIGHT be better for your function to take a Matrix as an argument, that way the scalar type should be available. Something like this:

template<class T, int rows, int cols, int opts, int maxR, int maxC > 
void myFunc( Eigen::Matrix<T, rows, cols, opts, maxR, maxC>& matrix )
{
    T tmp = matrix(0, 0);
}

(Looks dreadful though!!! ;-) )

Upvotes: 1

rubenvb
rubenvb

Reputation: 76519

In your code, Type1 is deduced to be double (because Eigen::MatrixXd is defined that way).

You are then trying to do

Type1 tmp = matrix(0, 0);

And I'm afraid my Eigen knowledge isn't enough, so I ran it through Clang 3.3, and got this error:

test.cpp:9:7: error: no viable conversion from 'Scalar' (aka 'double') to
      'Eigen::Matrix<double, -1, -1, 0, -1, -1>'
Type1 tmp = matrix(0, 0);           // getting compiler error here
      ^     ~~~~~~~~~~~~
test.cpp:17:1: note: in instantiation of function template specialization
      'myFunc<Eigen::Matrix<double, -1, -1, 0, -1, -1> >' requested here
myFunc(m);
^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:210:5: note: candidate constructor not viable:
      no known conversion from 'Scalar' (aka 'double') to
      'internal::constructor_without_unaligned_array_assert' for 1st argument
    Matrix(internal::constructor_without_unaligned_array_assert)
    ^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:284:25: note: candidate constructor not
      viable: no known conversion from 'Scalar' (aka 'double') to 'const
      Eigen::Matrix<double, -1, -1, 0, -1, -1> &' for 1st argument
    EIGEN_STRONG_INLINE Matrix(const Matrix& other)
                        ^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:272:25: note: candidate template ignored:
      could not match 'MatrixBase<type-parameter-0-0>' against 'double'
    EIGEN_STRONG_INLINE Matrix(const MatrixBase<OtherDerived>& other)
                        ^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:292:25: note: candidate template ignored:
      could not match 'ReturnByValue<type-parameter-0-0>' against 'double'
    EIGEN_STRONG_INLINE Matrix(const ReturnByValue<OtherDerived>& other)
                        ^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:303:25: note: candidate template ignored:
      could not match 'EigenBase<type-parameter-0-0>' against 'double'
    EIGEN_STRONG_INLINE Matrix(const EigenBase<OtherDerived> &other)
                        ^
1 error generated.

which is telling me you cannot call matrix like that, with two 0's as arguments. It's also weird syntax because the MatrixBase class does not have an operator() which you seem to be trying to calling.

Upvotes: 0

Related Questions