Currently, Eigen seems to rely on static asserts to prevent calling inappropriate methods (e.g. `w()` on a `Matrix<T, 3, 1>`). This makes it impossible to explicitly instantiate non-Dynamic matrices, or (more interestingly) any user classes derived from the same. These methods should instead use enable_if so that they simply don't exist if the static conditions are not satisfied. (I suppose all instances of EIGEN_STATIC_ASSERT should ideally be reviewed.) In particular, at least the following code should compile: #include <Eigen/Core> template class Eigen::Matrix< int, 2, 1 >; template class Eigen::Matrix< float, 3, 1 >; template class Eigen::Matrix< double, 4, 1 >;
How would that work? Things like this don't work (this is not how SFINAE works): template<int N> struct Vector { double data[N]; std::enable_if<(N==1), double>::type value() { return data[0]; } }; template struct Vector<2>; // still fails -> https://godbolt.org/z/N_vmg4 The only solution for your problem I see would be to explicitly specialize classes (which I don't think is worth the effort). If you really need to explicitly instantiate Eigen::Matrix templates, you could compile with `-DEIGEN_NO_STATIC_ASSERT`. But even with that, I don't really see a point of doing it. You will never instantiate all possible assignments, e.g., doing anything useful like this will still require the entire <Eigen/Core> to be included by the user: Matrix3f A; Vector3f b; Vector3f res = A*b; I'll mark this as WONTFIX, but I'm open to any (proof-of-concept) implementations which would make that work. Btw, if you cross-post, please refer the posts to each other: https://stackoverflow.com/questions/58630573/why-cant-i-inherit-from-eigenmatrix
That's... not how you use enable_if. The method itself has to *also* be a template on a type that resolves from the enable_if. (Reading https://en.cppreference.com/w/cpp/types/enable_if might help.) I'm pretty sure I've done something along these lines. I can't recall where offhand to dig up a working example, but I will try to do so, or just create one. (Probably won't be able to do it next week though.) Yeah, sorry, it's related to that SO question, but not really a duplicate, so I didn't think about cross-referencing.
(In reply to Matthew Woehlke from comment #2) > That's... not how you use enable_if. [...] That's what I said. But I don't see what kind of template you want to add to `value()` or `w()`, etc. Feel free to re-open, if you find a feasible way (but don't change this to FIXED, if nothing was fixed).
What you said is, "<misuse of enable_if> doesn't work"... which is sort of tautological. Honestly, until you read through https://en.cppreference.com/w/cpp/types/enable_if or some other example, you're not going to get it right; enable_if is screwy and somewhat counterintuitive, and I have yet to get it right on a first attempt and without re-reading that doc. Anyway, here's my attempt. I didn't try this in Eigen itself, but I did something similar for my own type, so I *think* this should work. At least, it should be much closer to functional: template< unsigned _N = _Rows, typename std::enable_if< _N == 3, bool >::type = true > EIGEN_DEVICE_FUNC/*?*/ EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) { Base::_check_template_params(); m_storage.data()[0] = x; m_storage.data()[1] = y; m_storage.data()[2] = z; } Note that a) the *method* is templated (i.e. this is a *nested* template), and b) you have to duplicate the argument that is used in the enable_if. If you don't do both (your attempt didn't, just like most of *my* first attempts), it won't work. (This probably also means that an explicit instantiation won't actually instantiate any such methods, but since right now the entire class can't be instantiated, that is still an improvement.) This is somewhat simplified; in practice, you probably also want to check the column count, probably want to allow dynamic size, and so forth. An "actual" implementation is probably going to be several lines of template parameters with a fairly complicated expression to enable_if. Hopefully, though, the above is at least enough to demonstrate feasibility.
Created attachment 961 [details] Possible patch for Matrix<> Note that this is only possible in C++11. Even though I'm also doubtful about the usefulness of this, here is a possible patch. If we agree on it I'll apply it to Array and add a unit test.
Looks plausible to me. The usefulness is that I can now write something like: class MY_EXPORT whatever : protected Eigen::Vector3d { ... } (Or I can just have my library declare and export instantiations of Eigen types, though I'm less Additionally, I believe it changes the error when using an inappropriate function from tripping a static_assert to a 'no matching function call' (albeit followed by a potentially cryptic candidate). Whether that's useful on its own is arguable.
Regarding error messages, the situation is kind of improved, for instance for: Vector3f v(1,2,3,4); In c++03 (so without init. list and without enable_if): In file included from bug1768.cpp:2: In file included from ../eigen/Eigen/Core:278: ../eigen/Eigen/src/Core/Matrix.h:396:7: error: no member named 'THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE' in 'Eigen::internal::static_assertion<false>' EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3) ^ ../eigen/Eigen/src/Core/util/StaticAssert.h:158:23: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE) ^ bug1768.cpp:4:23: note: in instantiation of member function 'Eigen::Matrix<int, 2, 1, 0, 2, 1>::Matrix' requested here template class Eigen::Matrix< int, 2, 1 >; ^ In file included from bug1768.cpp:2: In file included from ../eigen/Eigen/Core:278: ../eigen/Eigen/src/Core/Matrix.h:412:7: error: no member named 'THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE' in 'Eigen::internal::static_assertion<false>' EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) ^ ../eigen/Eigen/src/Core/util/StaticAssert.h:158:23: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE) ^ bug1768.cpp:4:23: note: in instantiation of member function 'Eigen::Matrix<int, 2, 1, 0, 2, 1>::Matrix' requested here template class Eigen::Matrix< int, 2, 1 >; ^ In file included from bug1768.cpp:2: In file included from ../eigen/Eigen/Core:278: ../eigen/Eigen/src/Core/Matrix.h:412:7: error: no member named 'THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE' in 'Eigen::internal::static_assertion<false>' EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) ^ ../eigen/Eigen/src/Core/util/StaticAssert.h:158:23: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE) ^ bug1768.cpp:5:23: note: in instantiation of member function 'Eigen::Matrix<float, 3, 1, 0, 3, 1>::Matrix' requested here template class Eigen::Matrix< float, 3, 1 >; ^ In file included from bug1768.cpp:2: In file included from ../eigen/Eigen/Core:278: ../eigen/Eigen/src/Core/Matrix.h:396:7: error: no member named 'THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE' in 'Eigen::internal::static_assertion<false>' EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3) ^ ../eigen/Eigen/src/Core/util/StaticAssert.h:158:23: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE) ^ bug1768.cpp:6:23: note: in instantiation of member function 'Eigen::Matrix<double, 4, 1, 0, 4, 1>::Matrix' requested here template class Eigen::Matrix< double, 4, 1 >; ^ bug1768.cpp:10:12: error: no matching constructor for initialization of 'Eigen::Vector3f' (aka 'Matrix<float, 3, 1>') Vector3f b(1.f,2.f,3.f,4); ^ ~~~~~~~~~~~~~ ../eigen/Eigen/src/Core/Matrix.h:329:14: note: candidate constructor template not viable: requires single argument 'x', but 4 arguments were provided explicit Matrix(const T& x) ^ ../eigen/Eigen/src/Core/Matrix.h:337:5: note: candidate constructor template not viable: requires 2 arguments, but 4 were provided Matrix(const T0& x, const T1& y) ^ ../eigen/Eigen/src/Core/Matrix.h:430:25: note: candidate constructor template not viable: requires single argument 'other', but 4 arguments were provided EIGEN_STRONG_INLINE Matrix(const EigenBase<OtherDerived> &other) ^ ../eigen/Eigen/src/Core/Matrix.h:441:14: note: candidate constructor template not viable: requires single argument 'r', but 4 arguments were provided explicit Matrix(const RotationBase<OtherDerived,ColsAtCompileTime>& r); ^ ../eigen/Eigen/src/Core/Matrix.h:393:25: note: candidate constructor not viable: requires 3 arguments, but 4 were provided EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) ^ ../eigen/Eigen/src/Core/Matrix.h:267:14: note: candidate constructor not viable: requires 1 argument, but 4 were provided explicit Matrix(internal::constructor_without_unaligned_array_assert) ^ ../eigen/Eigen/src/Core/Matrix.h:422:25: note: candidate constructor not viable: requires single argument 'other', but 4 arguments were provided EIGEN_STRONG_INLINE Matrix(const Matrix& other) : Base(other) ^ ../eigen/Eigen/src/Core/Matrix.h:259:5: note: candidate constructor not viable: requires 0 arguments, but 4 were provided Matrix() : Base() ^ 5 errors generated. and in c++11: In file included from bug1768.cpp:2: In file included from ../eigen/Eigen/Core:277: ../eigen/Eigen/src/Core/PlainObjectBase.h:546:7: error: static_assert failed "THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE" EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, sizeof...(args) + 4); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigen/Eigen/src/Core/util/StaticAssert.h:157:3: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime && TYPE::SizeAtCompileTime==SIZE, \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigen/Eigen/src/Core/util/StaticAssert.h:33:40: note: expanded from macro 'EIGEN_STATIC_ASSERT' #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG); ^ ~ ../eigen/Eigen/src/Core/Matrix.h:297:9: note: in instantiation of function template specialization 'Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1> >::PlainObjectBase<>' requested here : Base(a0, a1, a2, a3, args...) {} ^ bug1768.cpp:10:12: note: in instantiation of function template specialization 'Eigen::Matrix<float, 3, 1, 0, 3, 1>::Matrix<>' requested here Vector3f b(1.f,2.f,3.f,4); ^ In file included from bug1768.cpp:2: In file included from ../eigen/Eigen/Core:277: ../eigen/Eigen/src/Core/PlainObjectBase.h:552:12: error: cannot deduce actual type for variable 'x' with type 'auto' from initializer list auto x = {(m_storage.data()[i++] = args, 0)...}; ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 errors generated. Even though the second error message is rather cryptic, we get 2 errors instead of 5.
The cryptic error line can be removed by disabling: template <typename... ArgTypes, typename Enable = typename internal::enable_if< IsVectorAtCompileTime && (sizeof...(ArgTypes)+4) == SizeAtCompileTime >::type> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) In this case we get: bug1768.cpp:10:12: error: no matching constructor for initialization of 'Eigen::VectorXf' (aka 'Matrix<float, Dynamic, 1>') VectorXf b{1.f,2.f,3.f,4.f}; ^~~~~~~~~~~~~~~~~~ ../eigen/Eigen/src/Core/Matrix.h:297:5: note: candidate template ignored: substitution failure [with ArgTypes = <>]: implicit instantiation of undefined template 'Eigen::internal::enable_if<false, void>' Matrix(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) ^ ../eigen/Eigen/src/Core/Matrix.h:410:25: note: candidate template ignored: substitution failure [with Size = -1]: implicit instantiation of undefined template 'Eigen::internal::enable_if<false, void>' EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) ^ ../eigen/Eigen/src/Core/Matrix.h:330:14: note: candidate constructor template not viable: requires single argument 'x', but 4 arguments were provided explicit Matrix(const T& x) ^ ../eigen/Eigen/src/Core/Matrix.h:338:5: note: candidate constructor template not viable: requires 2 arguments, but 4 were provided Matrix(const T0& x, const T1& y) ^ ../eigen/Eigen/src/Core/Matrix.h:394:25: note: candidate constructor template not viable: requires 3 arguments, but 4 were provided EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) ^ ../eigen/Eigen/src/Core/Matrix.h:431:25: note: candidate constructor template not viable: requires single argument 'other', but 4 arguments were provided EIGEN_STRONG_INLINE Matrix(const EigenBase<OtherDerived> &other) ^ ../eigen/Eigen/src/Core/Matrix.h:442:14: note: candidate constructor template not viable: requires single argument 'r', but 4 arguments were provided explicit Matrix(const RotationBase<OtherDerived,ColsAtCompileTime>& r); ^ ../eigen/Eigen/src/Core/Matrix.h:267:14: note: candidate constructor not viable: requires 1 argument, but 4 were provided explicit Matrix(internal::constructor_without_unaligned_array_assert) ^ ../eigen/Eigen/src/Core/Matrix.h:273:5: note: candidate constructor not viable: requires single argument 'other', but 4 arguments were provided Matrix(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_constructible<Scalar>::value) ^ ../eigen/Eigen/src/Core/Matrix.h:322:34: note: candidate constructor not viable: requires single argument 'list', but 4 arguments were provided explicit EIGEN_STRONG_INLINE Matrix(const std::initializer_list<std::initializer_list<Scalar>>& list) : Base(list) {} ^ ../eigen/Eigen/src/Core/Matrix.h:423:25: note: candidate constructor not viable: requires single argument 'other', but 4 arguments were provided EIGEN_STRONG_INLINE Matrix(const Matrix& other) : Base(other) ^ ../eigen/Eigen/src/Core/Matrix.h:259:5: note: candidate constructor not viable: requires 0 arguments, but 4 were provided Matrix() : Base() ^ 1 error generated. instead of (with current head): In file included from bug1768.cpp:2: In file included from ../eigenfresh/Eigen/Core:278: ../eigenfresh/Eigen/src/Core/Matrix.h:392:7: error: static_assert failed "THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE" EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:157:3: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime && TYPE::SizeAtCompileTime==SIZE, \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:33:40: note: expanded from macro 'EIGEN_STATIC_ASSERT' #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG); ^ ~ bug1768.cpp:4:23: note: in instantiation of member function 'Eigen::Matrix<int, 2, 1, 0, 2, 1>::Matrix' requested here template class Eigen::Matrix< int, 2, 1 >; ^ In file included from bug1768.cpp:2: In file included from ../eigenfresh/Eigen/Core:278: ../eigenfresh/Eigen/src/Core/Matrix.h:404:7: error: static_assert failed "THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE" EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:157:3: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime && TYPE::SizeAtCompileTime==SIZE, \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:33:40: note: expanded from macro 'EIGEN_STATIC_ASSERT' #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG); ^ ~ bug1768.cpp:4:23: note: in instantiation of member function 'Eigen::Matrix<int, 2, 1, 0, 2, 1>::Matrix' requested here template class Eigen::Matrix< int, 2, 1 >; ^ In file included from bug1768.cpp:2: In file included from ../eigenfresh/Eigen/Core:278: ../eigenfresh/Eigen/src/Core/Matrix.h:404:7: error: static_assert failed "THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE" EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:157:3: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime && TYPE::SizeAtCompileTime==SIZE, \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:33:40: note: expanded from macro 'EIGEN_STATIC_ASSERT' #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG); ^ ~ bug1768.cpp:5:23: note: in instantiation of member function 'Eigen::Matrix<float, 3, 1, 0, 3, 1>::Matrix' requested here template class Eigen::Matrix< float, 3, 1 >; ^ In file included from bug1768.cpp:2: In file included from ../eigenfresh/Eigen/Core:278: ../eigenfresh/Eigen/src/Core/Matrix.h:392:7: error: static_assert failed "THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE" EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:157:3: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime && TYPE::SizeAtCompileTime==SIZE, \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:33:40: note: expanded from macro 'EIGEN_STATIC_ASSERT' #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG); ^ ~ bug1768.cpp:6:23: note: in instantiation of member function 'Eigen::Matrix<double, 4, 1, 0, 4, 1>::Matrix' requested here template class Eigen::Matrix< double, 4, 1 >; ^ In file included from bug1768.cpp:2: In file included from ../eigenfresh/Eigen/Core:278: ../eigenfresh/Eigen/src/Core/Matrix.h:404:7: error: static_assert failed "THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE" EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:157:3: note: expanded from macro 'EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE' EIGEN_STATIC_ASSERT(TYPE::IsVectorAtCompileTime && TYPE::SizeAtCompileTime==SIZE, \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../eigenfresh/Eigen/src/Core/util/StaticAssert.h:33:40: note: expanded from macro 'EIGEN_STATIC_ASSERT' #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG); ^ ~ bug1768.cpp:10:12: note: in instantiation of member function 'Eigen::Matrix<float, -1, 1, 0, -1, 1>::Matrix' requested here VectorXf b{1.f,2.f,3.f,4.f}; ^ 5 errors generated.
Created attachment 962 [details] Complete patch. Here is the complete patch that I'm willing to apply.
-- GitLab Migration Automatic Message -- This bug has been migrated to gitlab.com's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.com/libeigen/eigen/issues/1768.