TMP (шаблон метапрограммирования) с Eigen: простой * бинарный оператор не компилируется с расширенным типом Eigen::Matrix
Следуя примеру для расширения Eigen::Types
здесь, в разделе "Наследование от матрицы", я создал небольшое изменение примера:
class MyType : public Eigen::Vector3d {
public:
MyType(void) : Eigen::Vector3d() {}
template<typename OtherDerived> // MyType ctor from Eigen expressions
MyType(const Eigen::MatrixBase<OtherDerived>& other)
: Eigen::Vector3d(other) {}
// ... operator= as in the example, not shown to save some space ...
// ONLY NEW CODE: a new binary operator ^ returning Matrix3d
template<typename OtherDerived>
Eigen::Matrix3d operator^ (const Eigen::MatrixBase<OtherDerived>& other) {
return Eigen::Matrix3d{ *this * other.transpose() };
}
};
Новый бинарный оператор ^
выполняет свою работу только условно, как показано ниже:
MyType t1; t1.setRandom(); std::cout << "t1 is:\n" << t1 << std::endl;
MyType t2; t2.setRandom(); std::cout << "t2 is:\n" << t2 << std::endl;
Eigen::Matrix3d t3 = t1 ^ t2; std::cout << "t3 is:\n" << t3 << std::endl; // works
const double fac1{ 10.0 }; // invoke using multiplication factors
t3 = t1 ^ t2*fac1; // and t1 ^ fac1*t2 also works, output is correct
t3 = t1*fac1 ^ t2; // does not compile. Neither does t1*fac1 ^ t2.
Я могу использовать стандарт *
бинарный оператор со скаляром и Vector3d
в качестве операндов (поддерживается Eigen). Но это работает только на втором операнде моего нового ^
бинарный оператор. Исходя из приоритета оператора и, возможно, некоторого ADL (аргументно-зависимого поиска), я ожидаю, что компилятор разберется с ними. Теперь вот сообщение об ошибке компилятора (в стиле кода для удобства чтения):
myCode.cpp(43) : error C2676: binary '^' :
'const Eigen::CwiseUnaryOp<Eigen::internal::scalar_multiple_op<double>,const Derived>'
does not define this operator or a conversion to a type acceptable to the
predefined operator with
[ Derived=Eigen::Matrix<double,3,1,0,3,1> ]
Должен ли я сделать вывод, что компилятор так или иначе думает *
в t1*fac1
такое унарный оператор? Почему это не было проблемой, когда он был применен на t2
чей тип точно такой же, как у t1
, Пробовал вложить между паратезами так: (fac1*t1) ^ t2
, но не сработало. Я также определил свой собственный operator* (const double&)
со скаляром и MyType
как операнды, но в приведенной выше строке кода была точно такая же ошибка компиляции.
Может ли это быть Eigen
или ошибка компилятора? Я использую MS Visual C++ 2015. Я что-то упустил? Любой свет, который вы можете пролить на этот вопрос, приветствуется.
2 ответа
Лучший способ расширить API Eigen - это не создавать подклассы Matrix
но либо добавив методы к Эйгена DenseBase
, MatrixBase
, или же Matrix
классы через механизм плагинов или путем реализации шаблонных свободных функций. В вашем случае последний вариант самый простой. С Eigen 3.3:
template<typename A,typename B>
Product<A,Transpose<const B> >
operator^(const MatrixBase<A> &a,const MatrixBase<B> &b) {
return a * b.transpose();
}
И вы сделали.
Я думаю, что ваша проблема абстрактно может быть следующей. В первом случае, который работает, t2*fac1 сначала вычисляет и возвращает временный объект некоторого базового типа, а затем оператор ^ вызывается с t2, поскольку это имеет тип MyType, а второй аргумент является временным значением. Во втором случае, однако, сначала выполняется t1*fac1, и вы также возвращаете объект некоторого базового типа, но на этот раз он пытается вызвать оператор ^ для этого объекта базового типа, который, по вашему мнению, не реализован в таком базовом типе.
Вы сказали, что реализовали оператор * с двойным и MyType в качестве операндов, это был оператор члена класса? может быть, вы можете попробовать что-то подобное и убедиться, что этот оператор вызывается в обоих случаях, а не в базовом классе:
MyType operator*(const double&); // MyType as a member operator.