2009/3/31 Patrick Mihelich <patrick.mihelich@xxxxxxxxx>:
> Hi again,Yes, in fact we have simply no choice. A MatrixBase may be any
> Currently all of the MatrixBase const accessor functions return const
> Scalar, while the non-const version return (of course) Scalar&. Is there a
> rationale for returning by value in the const versions instead of const
_expression_. As soon as an _expression_ represents a nontrivial
computation (like a sum of two matrices) there is no way that coeff()
could return a reference : a reference to what? the result isn't
stored permanently in memory.
OK, right. But you do not always have to use the lowest-common-denominator behavior (return by value). MatrixBase knows the Derived type and can return by const-reference for Derived types with dense storage (Matrix, Map).
The "standard C++" approach is to give MatrixBase three typedefs: value_type, reference (return type of non-const accessors, convertible to value_type), and const_reference (return type of const accessors, convertible to value_type); then use these to define your accessors. STL/Boost users will recognize these names but you could certainly use friendlier ones like Scalar, ScalarRef, and ScalarConstRef:
ScalarRef operator() (int index);
ScalarConstRef operator() (int index) const;
ScalarRef operator() (int row, int col);
ScalarConstRef operator() (int row, int col) const;
For dense storage types:
typedef Scalar& ScalarRef;
typedef const Scalar& ScalarConstRef;
For _expression_ types:
typedef Scalar ScalarRef;
typedef Scalar ScalarConstRef;
> I don't like this inconsistent behavior. Sometimes I want to get a
> pointer to a chunk of memory in a Matrix so I can pass it to some low-levelAbove you were talking about MatrixBase; now with Matrix it's
> function, like foo( &mat(r, c) ).
different, indeed the coefficients do exist in memory, and if you look
at the Matrix class, the coeff() methods do return const references,
exactly like you want!
If you have a MatrixBase that happens to be a Matrix, you can always
use the derived() method to get the matrix:
void foo(const MatrixBase& m)
float *ptr = &(m.derived().coeff(i,j));
in fact derived() just casts 'this' to a Matrix pointer, and indirects.
OK but this is more verbose, and it's rather surprising that it doesn't do the same thing as m(i,j) or even m.coeff(i,j). I do not think Matrix should override the coeff() methods from MatrixBase with different signatures; more generally I'd suggest that for any MatrixBase method foo, m.foo() and m.derived().foo() should always behave identically.
BTW, there is a mistake in MapBase: const Scalar coeff(int index) const should return const Scalar&.
That's another issue. But the above-mentioned fact that xpressions
> This breaks when mat is a const type like
> const Matrix&. I can also imagine wanting to use Eigen matrices with types
> that are not trivially cheap to copy (arbitrary precision types, for
> example), when returning by value may result in an unwanted copy.
have no choice but to return by value, is unavoidable. So I think that
the best solution then, is that the "heavy numeric types" in question
be endowed with a copy-on-write mechanism so that these copies become