7

I am trying to return a block of a matrix as an lvalue of a function. Let's say my function looks like this:

Block<Derived> getBlock(MatrixXd & m, int i, int j, int row, int column)
{
    return m.block(i,j,row,column);
}

As it turns out, it seems that C++ compiler understands that block() operator gives only temporary value and so returning it as an lvalue is prohibited by the compiler. However, in Eigen documentation there is some example that we can use Eigen as an lvalue (http://eigen.tuxfamily.org/dox/TutorialBlockOperations.html#TutorialBlockOperationsUsing) so I am wondering how we couldn't do the same with function return.

a.block(0,0,2,3) = a.block(2,1,2,3);

Thank you!

HuaTham
  • 7,486
  • 5
  • 31
  • 50

2 Answers2

8

I want to put what I found myself so it might be helpful to someone else:

My basic solution is to know what derived type you want the block to be. In this case:

Block<MatrixXd> getBlock(MatrixXd & m, int i, int j, int row, int column)
{
    return m.block(i,j,row,column);
}

It is interesting to me to notice that this method will return the reference to the content of matrix m by default. So if we do:

MatrixXd m = MatrixXd::Zero(10,10);
Block<MatrixXd> myBlock = getBlock(m, 1, 1, 3, 3);
myBlock << 1, 0, 0, 
           0, 1, 0, 
           0, 0, 1;

The content in matrix m will be modified as well. Note that, however,

MatrixXd m = MatrixXd::Zero(10,10);
MatrixXd myBlock = getBlock(m, 1, 1, 3, 3);
myBlock << 1, 0, 0, 
           0, 1, 0, 
           0, 0, 1;

will not work. My understanding is that once we convert the block to another type Eigen makes a copy of the data before conversion.

HuaTham
  • 7,486
  • 5
  • 31
  • 50
  • 1
    thanks to expression templates, block() does not actually return a copy the block, instead it just returns an expression – m. c. Nov 11 '15 at 00:20
  • @user3183610 so how to force a block (an expression) to evaluate. I mean as a valid lvalue. – stanleyerror Jan 24 '16 at 15:27
  • 1
    @stanleyerror Either by calling eval() or by assigning it to an Array or Matrix type (read something that's not an expression). That's why the second example doesn't change the original matrix. The Block is an expression pointing to the elements in the original matrix but when you assign the block to another MatrixXd variable, the expression is evaluated and the result stored in the variable. That variable now obviously has its own memory as with any `MatrixXd mat = other_mat` assignment. – Stefan Fabian Apr 24 '19 at 14:08
0

I was trying something like this, specifically returning the last 3 elements of a 4 element vector and I couldn't get this to work.

Solution turned out kind of nice, although maybe a little confusing if you're not familiar with trailing return types:

struct foo{

  Eigen::Vector4d e_;

  // const version
  auto get_tail() const -> const auto { return e_.tail<3>(); };

  // non-const version
  auto get_tail() -> auto { return e_.tail<3>(); };

};
schrödinbug
  • 692
  • 9
  • 19