1

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?

Tom de Geus
  • 5,625
  • 2
  • 33
  • 77
  • `const T &data` produces almost exact match (modulo constness and valueness), presumably you want to disable this overload with a SFINAE check – Piotr Skotnicki Nov 18 '18 at 18:34
  • @PiotrSkotnicki In overload resolution, binding `const T&` to `T` is considered an exact match. – Brian Bi Nov 18 '18 at 18:36
  • @Brian still better than derived to base conversion – Piotr Skotnicki Nov 18 '18 at 18:40
  • @PiotrSkotnicki Thanks. Just to clarify I should disallow Eigen objects from `const T &`? How do I do that? Why does this not happen for an `std::vector` overload? – Tom de Geus Nov 18 '18 at 18:47
  • @TomdeGeus because a function accepting `std::vector` produces equally good match but this one is more specialized that the one accepting `const T&`. the first condition does not hold for `MatrixBase`, which requires derived to base conversion, so partial ordering is not considered at all – Piotr Skotnicki Nov 18 '18 at 18:50
  • @PiotrSkotnicki I see. What is the best strategy to disable Eigen objects from the SFINAE check? – Tom de Geus Nov 18 '18 at 18:52

1 Answers1

2

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

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160