Search code examples
c++eigeneigen3

Overload Eigen::MatrixBase<T>


I have a function for which I have several templated overloads. I which to add an Eigen overload to it. I want to be general such as to be able to accept any Eigen matrix. Therefore I use Eigen::MatrixBase<T>. The problem kicks in with the overload, where the compiler fails to recognise the closest match with Eigen::MatrixBase<T>. Here is my code:

#include <iostream>
#include <Eigen/Eigen>

template <class T>
void foo(const Eigen::MatrixBase<T> &data)
{
  std::cout << "Eigen" << std::endl;
}

// ... several other overloads

template <class T>
void foo(const T &data)
{
  std::cout << "other" << std::endl;
}

int main()
{
  Eigen::VectorXd a(2);

  a(0) = 0.;
  a(1) = 1.;

  foo(a);
}

Whereby the output is other. How can I make the Eigen overload such that it is the closest match for any Eigen matrix?


Solution

  • Eigen::VectorXd is a typedef for Eigen::Matrix<double, Dynamic, 1>. Going foward, Eigen::MatrixBase<T> is a base class for Eigen::Matrix<T>. In overload resolution, reference binding of an instance of Eigen::VectorXd to the deduced const Eigen::VectorXd& parameter has the Exact Match rank which wins with Derived-to-Base conversion (required by void foo(const Eigen::MatrixBase<T>&).

    As a solution, you can disable the function template producing the exact match with a SFINAE check, so that it is excluded from the set of candidates, leaving the one requiring the derived-to-base conversion the only viable function.

    #include <type_traits>
    #include <utility>
    
    namespace detail
    {
        template <typename T>
        std::true_type test(const volatile Eigen::MatrixBase<T>&);
        std::false_type test(...);
    }
    
    template <typename T>
    using is_eigen_matrix = decltype(detail::test(std::declval<T&>()));
    
    template <class T>
    void foo(const Eigen::MatrixBase<T>& data)
    {
    }
    
    template <class T>
    auto foo(const T& data)
        -> typename std::enable_if<not is_eigen_matrix<T>::value>::type
    {
    }
    

    DEMO