shanksk
shanksk

Reputation: 115

Eigen parameters passing by reference

I'm following this page in the Eigen documentation an trying to understand the use of Eigen parameters

https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

The following code works as expected

#include <iostream>
#include <Eigen/Dense>

// a - nonwriteable, b - writeable
void eigen_reference_class(
    const Eigen::Ref<const Eigen::Array<double, 
    Eigen::Dynamic, 3> >& a, Eigen::Ref<Eigen::Array<double, Eigen::Dynamic, 3> > b) {
    b = 2 * a;
}

void eigen_reference(const Eigen::Array<double, 1, 3>& a, Eigen::Array<double, 1, 3>& b) {
    b = 2*a;
}

template<typename Derived> 
void eigen_template(const Eigen::PlainObjectBase<Derived>& a, Eigen::PlainObjectBase<Derived>& b) {
    b = 2*a;
}

int main()
{
    Eigen::Array<double, 1, 3> a, b, c, d;
    a << 1, 2, 3;
    eigen_reference_class(a, b);
    eigen_reference(a, c);
    eigen_template(a,  d);
    std::cout << "a : \n" << a << std::endl;
    std::cout << "b: \n" << b << std::endl;
    std::cout << "c: \n" << c << std::endl;
    std::cout << "d: \n" << d << std::endl;

}

However, if the initial declaration for the arrays is changed to

Eigen::Array<double, Eigen::Dynamic, 3> a, b, c, d;

Then the program will either fail to compile with the following:

error: invalid initialization of non-const reference of type ‘Eigen::Array<double, 1, 3>&’ from an rvalue of type ‘Eigen::Array<double, 1, 3>’       
     eigen_reference(a, c);

Or will fail with a segmentation fault even if only the definition of a is kept.

Upvotes: 0

Views: 1325

Answers (1)

Henri Menke
Henri Menke

Reputation: 10939

I like looking at what int does in such situations because it helps me understand the more complex things happening in this case easier.

Imagine you have a struct holding an int which is implicitly convertible to an int, so that you can use it in place of an int, like so:

struct Integer {
    int m_int;
    operator int() { return m_int; }
};

Now define two functions, one taking an int const & and one taking an int &.

void const_ref(int const &) {}
void ref(int &) {}

If we use a regular integer in those functions, there are no suprises.

int j = 3;
const_ref(j);
ref(j);

But if we use Integer instead it does not compile anymore.

Integer i{2};
const_ref(i);
ref(i);

The error is something like

error: no matching function for call to 'ref'
    ref(i);
    ^~~
note: candidate function not viable: no known conversion from 'Integer' to 'int &' for 1st argument
void ref(int &) {}
     ^
1 error generated.

Now the question is, why does const_ref work but ref doesn't?

In the call to const_ref what happens is that the conversion operator to int is called, which returns a temporary int to which we can bind a constant reference. We cannot bind a mutable reference to this temporary because this would lead to weird effects. Imagine that the function ref modifies the argument, but in this case it would modify a temporary and nothing would be written to the original Integer which you passed in... a guaranteed bug.


In your code it's the same. Eigen::Array<double, Eigen::Dynamic, 3> can implicitly convert to Eigen::Array<double, 1, 3> but you cannot bind a mutable reference to a temporary.

Upvotes: 1

Related Questions