Search code examples
c++11eigeneigen3

Eigen: Returning pointer with unaryExpr


I've got a struct that contains a pointer to a second struct, and I'm trying to use a unaryExpr to return the pointer. But it keeps removing the pointer and giving an error about mixed numeric types.

Reproducible example:

#include <Eigen/Core>

struct s1 {
    double d_;
};

struct s2 {
    s1* struc_;
};

int main() {
    s1 a;
    a.d_ = 1.0;

    s2 a_ptr;
    a_ptr.struc_ = &a;

    Eigen::Matrix<s2,1,1> in(1,1);
    in(0,0) = a_ptr;
    Eigen::Matrix<s1*,1,1> out(1,1);

    //Compiles
    out(0,0) = in(0,0).struc_;

    //Doesn't compile
    out = in.unaryExpr([](s2 x) { return x.struc_; });
}

Also here in compiler explorer


Solution

  • The problem lies in the way Eigen defines result_of:

    #if EIGEN_HAS_STD_RESULT_OF
    template<typename T> struct result_of {
      typedef typename std::result_of<T>::type type1;
      typedef typename remove_all<type1>::type type;
    };
    #else
    //...
    

    where the remove_all removes the pointer of the type. I will check if changing this breaks anything else, but putting pointers into matrices is not really what they are designed for.

    You can workaround the issue by wrapping your pointer into a trivial pointer-wrapper:

    template<class X> 
    struct Ptr {
        X* ptr;
        operator X*() const {return ptr;}
        X& operator*() const {return *ptr;}
        X* operator->() const {return ptr;}
        Ptr(X* p = 0) : ptr(p) {}
        Ptr& operator=(X* p) {ptr = p; return *this;}
    };
    

    and replacing every s1* by Ptr<s1>: https://godbolt.org/z/b_EtDw