3
votes

The Eigen documentation is filled with examples illustrating how one should write a general function accepting a matrix:

template <typename Derived>
void print_cond(const MatrixBase<Derived>& a)

The reason to use MatrixBase as opposed to Matrix is that all dense Eigen matrix expressions derive from MatrixBase. So, for instance, if I pass a block of a matrix

print_cond ( A.block(...));

Then using the signature const MatrixBase<Derived>& a avoids creating a temporary. Conversely, if we had declared the function with the signature

template <typename T, int rows, int cols>
void print_cond(const Matrix<T,rows,cols>& a)

then Eigen would have to convert the block type to a matrix before passing it to the function, meaning that an unnecessary temporary would have to be created.

Please correct me if this understanding is incorrect...

With that in mind, one of the benefits of the second approach is that we can get compile time checks on the dimensions of the matrix (assuming they are fixed, not dynamic).

What I can't find in the documentation is an example with the generality of the first approach (which helps avoid temporary creation), but which has complie time checks on the type and dimensions of the matrix. Could somebody please tell me how to do that?

1
Is Derived in the first example deduced to Matrix<T,rows,cols>?super
That is the heart of the question. Essentially the answer is no. For instance, when you pass A.block (...), it will be a different type. In Eigen the types can get very very complicated, so I am asking how to ensure the size and other matrix properties despite these complicated types.bremen_matt
Another example is when I create a Ref or Mapbremen_matt
Do you know T, rows, and cols? And does const Ref<const ...>& work for you?chtz
The easiest is to add some (static_)assert inside your function, unless you want the checks for overloading purposes. MatrixBase has RowsAtCompileTime / rows, etc.Marc Glisse

1 Answers

5
votes

Just for completeness, Marc and ggael are suggesting something like this

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

using namespace Eigen;

using T = double;

const int rows = 5;
const int cols = 3;

template<typename Derived>
void print_cond(const MatrixBase <Derived> &a) {

    /* We want to enforce the shape of the input at compile-time */
    static_assert(rows == Derived::RowsAtCompileTime);
    static_assert(cols == Derived::ColsAtCompileTime);

    /* Now that we are guaranteed that we have the
     * correct dimensions, we can do something... */
    std::cout << a;
}

int main() {
    print_cond(Matrix<T, rows, cols>::Ones());

    /* These will not compile */
    // print_cond(Matrix<T, rows + 1, cols>::Ones());
    // print_cond(Matrix<T, rows, cols + 1>::Ones());
    // print_cond(Matrix<T, rows + 1, cols + 1>::Ones());
    return 0;
}