jkjkjk
jkjkjk

Reputation: 121

Template deduction with Eigen arguments

template <typename Derived>
void Fun(const std::vector<Eigen::MatrixBase<Derived>> &seqs);

void Test() {
  std::vector<Eigen::MatrixXd> _seqs;
  Fun(_seqs);
}

As tutored by functions taking eigen types, Eigen::MatrixBase<Derived> should accept Eigen::MatrixXd. However, the above code could not compiled with error message says mismatched types ‘Eigen::MatrixBase<Derived>’ and ‘Eigen::Matrix<double, -1, -1>’ and the template arguments deduction failed.

So why this happens and how should we deal with it?

Thanks

Upvotes: 3

Views: 846

Answers (3)

chtz
chtz

Reputation: 18807

I don't see a point in accepting a vector of Eigen::MatrixBase objects. I don't know your use case, but it usually only makes sense to store the actual Matrix objects inside the vector. And passing that to a templated function is easy:

template<class S, int rows, int cols> 
void func(std::vector<Eigen::Matrix<S, rows, cols> > const &) { }

Usage example

Note: You can add more template parameters, for template parameters which have defaults, e.g., MatrixOptions or the allocator of the vector. The same way, you can leave out template parameters, e.g., if S is always double.

Upvotes: 1

3CxEZiVlQ
3CxEZiVlQ

Reputation: 38415

You should declare function and variable like below

template <typename Derived>
void Fun(const std::vector<std::unique_ptr<Eigen::MatrixBase<Derived>>> &seqs);

std::vector<std::unique_ptr<Eigen::MatrixBase<Derived>>> _seqs;

And fill the vector with pointers to Eigen::MatrixXd:

_seq.emplace_back(new Eigen::MatrixXd);

UPDATE @chtz informed me that Eigen::MatrixBase (inherits struct EigenBase) has no virtual destructor. Thus my solution above is not proper. The only ways left

  1. Use std::transform() to get std::vector<Eigen::MatrixBase<Derived>*> from std::vector<std::unique_ptr<Eigen::MatrixBase<Derived>>>.
  2. Solution offered by @xskxzr

Upvotes: 1

xskxzr
xskxzr

Reputation: 13040

This is because the rule that template-name<T> as a whole parameter (ignoring reference and cv-qualifiers) can be deduced from D if D is derived from template-name<T> for some T. This rule does not apply for std::vector<template-name<T>>.

Even if you explicitly specify the type, since there is no valid conversion from std::vector<Derived> to std::vector<Base>, the call is still ill-formed.

Besides S.M.'s solution, you can use meta programming.

template <
    typename T,
    // enable only if T is derived from Eigen::MatrixBase<T>
    typename std::enable_if_t<std::is_base_of<Eigen::MatrixBase<T>, T>::value, int> = 0
>
void Fun(const std::vector<T>&);

Upvotes: 3

Related Questions