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?
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
{
}