Attempting to make a class that takes both a Eigen::Matrix3d
and Eigen::Vector4d
as constructor args and have run into an issue with ambiguity. Given the following test class,
class MyClass
{
public:
MyClass(const Eigen::Matrix3d& m)
{
}
MyClass(const Eigen::Vector4d& v)
{
}
};
If I then do the following,
int main(int argc, char** argv)
{
Matrix3d m;
MyClass t1(m.transpose());
}
this fails to compile with the following error,
call of overloaded ‘MyClass(Eigen::Transpose<Eigen::Matrix<double, 3, 3> >)’ is ambiguous
516 | MyClass t1(m.transpose());
| ^
note: candidate: ‘MyClass::MyClass(const Vector4d&)’
561 | MyClass(const Eigen::Vector4d& v)
| ^~~~~~~
note: candidate: ‘MyClass::MyClass(const Matrix3d&)’
556 | MyClass(const Eigen::Matrix3d& m)
It's not clear to me how to resolve this issue
You can create constructor templates to both accept Eigen::Transpose<...>
objects (that are returned by transpose()
) and concrete Matrix3d
and Matrix4d
objects.
I assume the operations in your two separate constructors will be very similar so you can combine them:
class MyClass {
public:
// One constructor template accepting both Matrix3d and Matrix4d:
template<class Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
MyClass(const Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>& m)
{
// here you can do what you did in the two separate constructors before
std::cout << Rows << ',' << Cols << '\n';
}
... and add a delegating constructor template for the Transpose
objects:
// delegating constructor taking an Eigen::Transpose object:
template<class Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
MyClass(const Eigen::Transpose<
Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>& t) :
// delegate to the constructor shown above:
MyClass(Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>(t))
{
std::cout << "(was delegated)\n";
}
};
Now all the following cases will work:
int main() {
Eigen::Matrix3d m3;
Eigen::Matrix4d m4;
MyClass t3(m3); // no delegation
MyClass t4(m4); // no delegation
MyClass t3t(m3.transpose()); // delegating
MyClass t4t(m4.transpose()); // delegating
}
Output:
3,3
4,4
3,3
(was delegated)
4,4
(was delegated)
If you only want to accept transpositions, remove the first constructor and the delegation:
class MyClass {
public:
template<class Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
MyClass(const Eigen::Transpose<
Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>& t)
{
Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> m(t);
// use `m` here
}
};