Неоднозначная перегрузка после арифметики между различными типами собственных матриц - PullRequest
0 голосов
/ 26 апреля 2018

Я столкнулся с проблемой перегрузки функции для различных типов собственных матриц (точнее, столбца и матрицы). Перегрузка терпит неудачу, когда ввод является результатом некоторой простой арифметики. В частности:

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

typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> MatD;
typedef Eigen::Matrix<double, Eigen::Dynamic,              1, Eigen::ColMajor> ColD;

ColD multiply(const ColD &A){ return 2. * A; }
MatD multiply(const MatD &A){ return 2. * A; }

int main()
{
  ColD A = ColD::Ones(10);
  MatD B = MatD::Ones(10,10);

  // overload is correct
  std::cout << multiply(A) << std::endl;
  std::cout << multiply(B) << std::endl;

  // compiler error: "error: call to 'multiply' is ambiguous"
  std::cout << multiply(A+A) << std::endl;
  std::cout << multiply(B+B) << std::endl;

  return 0;
}

т.е. перегрузка на основе A и B скомпилирована правильно. Но компилятор не может определить правильную перегрузку, когда я делаю A+A и B+B. Я мог бы решить эту проблему, выполнив две строки, возможно, используя некоторую временную переменную, но этого я не хочу делать. Как я могу заставить эту перегрузку работать для этого «однострочного»?

Полагаю, это особенность Эйгена, но я до сих пор не могу точно понять, какая именно особенность и как я могу ее избежать.

1 Ответ

0 голосов
/ 26 апреля 2018

Как поясняется в комментарии, операторы Эйгена создают не простые матрицы или векторы, а объекты операций (например, Eigen::CwiseBinaryOp<...>).

Вы можете преобразовать операцию в простую матрицу, например, так ...

std::cout << multiply(ColD(A + A)) << std::endl;
std::cout << multiply(MatD(B + B)) << std::endl;

... или создайте multiply шаблон, который принимает все виды форматов. Синтаксис становится немного уродливым, однако:

template <typename Derived>
Eigen::Matrix<
    typename Eigen::internal::traits<Derived>::Scalar,
    Eigen::internal::traits<Derived>::RowsAtCompileTime, 
    Eigen::internal::traits<Derived>::ColsAtCompileTime>
    multiply(const Derived& A) 
{
    return 2.0 * A;
}

Параметр шаблона Derived, который может быть матрицей, вектором или любым из объектов операций Эйгена. Возвращаемое значение - Eigen::Matrix, характеристики которого мы извлекаем из Derived с помощью шаблона traits.

...