I have a vector of shared pointers of functor objects: std::vector<std::shared_ptr<MyFunctor>>
and I would like to apply one of them to all the elements in an eigen MatrixXd
object.
The abstract base class MyFunctor
defines a member function operator()
that takes and returns a double
and is const. Derived classes implement the function.
It would seem that the unaryExpr
function would be appropriate, but I can't quite get the syntax correct.
I'm trying to do something like:
mat.unaryExpr( *(vectorOfFunctors[0]) );
I am adding an example with the work-around I found to work.
This is for MSVC 2019 (16.2.5) on Windows 10, 64 bit.
#include <Eigen/Dense>
#include <vector>
#include <memory>
class MyFunctorBase {
public:
virtual double operator()(double) const = 0;
virtual std::string getName() const = 0;
};
class MyFunctor : public MyFunctorBase {
public:
MyFunctor() {};
std::string getName() const { return "MyFunctor"; }
double operator()(double d) const { return d + 1; }
};
void func() {
std::shared_ptr<MyFunctor> mf1(new MyFunctor());
std::vector<std::shared_ptr<MyFunctorBase>> vectorOfFunctors;
vectorOfFunctors.push_back(mf1);
Eigen::MatrixXd A(2, 2);
A << 1, 2,
3, 4;
//Method 1
//Eigen::MatrixXd t0 = A.unaryExpr(*(vectorOfFunctors[0])); //Does not compile
//Method 2
const MyFunctorBase& mfb = *(vectorOfFunctors[0]); //Compiles
Eigen::MatrixXd t2 = A.unaryExpr(std::ref(mfb));
}
Eigen tries to instantiate an instance of the abstract functor you pass into it, hence the compile error. Note that because you dereference the pointer, you are passing in a sliced abstract object into the unaryExpr
method. You could just pass in the derived functor directly, or dynamic_cast
to the derived type before dereferencing.
The reason you get the expected behaviour with std::ref
, is that it wraps the MyFunctorBase
in a reference wrapper, so at the point of instantiation, you don't get the error about creating an abstract type. Later, when the functor is invoked, it implicitly converts to MyFunctorBase&
, allowing for the virtual operator()
call. Following on from this, you could have a std::vector
of reference wrapper objs (std::vector<std::reference_wrapper<MyFunctorBase>>
), rather than manually wrapping each element in the container with std::ref
.
Note that Eigen matrices provide iterators that are compatible with STL algorithms, and you can achieve the same goal with std::transform
.