From 218c37beb4dbc701938da71acf0bd3914f34f89e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 31 Aug 2016 15:45:25 +0200 Subject: bug #1286: automatically detect the available prototypes of functors passed to CwiseNullaryExpr such that functors have only to implement the operators that matters among: operator()() operator()(i) operator()(i,j) Linear access is also automatically detected based on the availability of operator()(i,j). --- test/nullary.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'test/nullary.cpp') diff --git a/test/nullary.cpp b/test/nullary.cpp index cb87695ee..ad306c1e9 100644 --- a/test/nullary.cpp +++ b/test/nullary.cpp @@ -104,13 +104,29 @@ void testVectorType(const VectorType& base) template void testMatrixType(const MatrixType& m) { + using std::abs; const Index rows = m.rows(); const Index cols = m.cols(); + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + Scalar s1; + do { + s1 = internal::random(); + } while(abs(s1)::IsInteger)); MatrixType A; A.setIdentity(rows, cols); VERIFY(equalsIdentity(A)); VERIFY(equalsIdentity(MatrixType::Identity(rows, cols))); + + + A = MatrixType::Constant(rows,cols,s1); + Index i = internal::random(0,rows-1); + Index j = internal::random(0,cols-1); + VERIFY_IS_APPROX( MatrixType::Constant(rows,cols,s1)(i,j), s1 ); + VERIFY_IS_APPROX( MatrixType::Constant(rows,cols,s1).coeff(i,j), s1 ); + VERIFY_IS_APPROX( A(i,j), s1 ); } void test_nullary() @@ -137,4 +153,22 @@ void test_nullary() // Assignment of a RowVectorXd to a MatrixXd (regression test for bug #79). VERIFY( (MatrixXd(RowVectorXd::LinSpaced(3, 0, 1)) - RowVector3d(0, 0.5, 1)).norm() < std::numeric_limits::epsilon() ); #endif + +#ifdef EIGEN_TEST_PART_10 + // check some internal logic + VERIFY(( internal::has_nullary_operator >::value )); + VERIFY(( !internal::has_unary_operator >::value )); + VERIFY(( !internal::has_binary_operator >::value )); + VERIFY(( internal::functor_has_linear_access >::ret )); + + VERIFY(( !internal::has_nullary_operator >::value )); + VERIFY(( !internal::has_unary_operator >::value )); + VERIFY(( internal::has_binary_operator >::value )); + VERIFY(( !internal::functor_has_linear_access >::ret )); + + VERIFY(( !internal::has_nullary_operator >::value )); + VERIFY(( internal::has_unary_operator >::value )); + VERIFY(( !internal::has_binary_operator >::value )); + VERIFY(( internal::functor_has_linear_access >::ret )); +#endif } -- cgit v1.2.3 From e13071dd13233b5d07e725453617c40421cf7501 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 5 Sep 2016 15:50:41 +0200 Subject: Workaround a weird msvc 2012 compilation error. --- Eigen/src/Core/CoreEvaluators.h | 55 +++++++++++++++++++++++++++++++++++++++++ Eigen/src/Core/util/Meta.h | 10 ++++---- test/nullary.cpp | 14 +++++++++++ 3 files changed, 74 insertions(+), 5 deletions(-) (limited to 'test/nullary.cpp') diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index 9b90543c3..a3fb253c0 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -393,6 +393,61 @@ struct nullary_wrapper template struct nullary_wrapper {}; +#if EIGEN_COMP_MSVC>0 && EIGEN_COMP_MSVC<=1700 + +// MSVC 2012 (and probably older ones too) exhibits a weird compilation error when +// compiling: +// Eigen::MatrixXf A = MatrixXf::Random(3,3); +// Ref R = 2.f*A; +// and that has_*ary_operator> have not been instantiated yet. +// The "problem" is that evaluator<2.f*A> is instantiated by traits::match<2.f*A> +// and at that time has_*ary_operator returns true regardless of T. +// Then nullary_wrapper is badly instantiated as nullary_wrapper<.,.,true,true,true>. +// The trick is thus to defer the proper instantiation of nullary_wrapper when coeff(), +// and packet() are really instantiated as implemented below: + +// This is a simple wrapper around Index to enforce the re-instantiation of +// has_*ary_operator when needed. +template struct nullary_wrapper_workaround_msvc_2012 { + nullary_wrapper_workaround_msvc_2012(const T&); + operator T()const; +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i,j); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i,j); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i); + } +}; +#endif // MSVC<=2012 workaround + template struct evaluator > : evaluator_base > diff --git a/Eigen/src/Core/util/Meta.h b/Eigen/src/Core/util/Meta.h index bbef83ea8..d4460bb77 100755 --- a/Eigen/src/Core/util/Meta.h +++ b/Eigen/src/Core/util/Meta.h @@ -383,7 +383,7 @@ struct has_ReturnType template const T& return_ref(); -template +template struct has_nullary_operator { template static meta_yes testFunctor(C const *,typename enable_if<(sizeof(return_ref().operator()())>0)>::type * = 0); @@ -392,19 +392,19 @@ struct has_nullary_operator enum { value = sizeof(testFunctor(static_cast(0))) == sizeof(meta_yes) }; }; -template +template struct has_unary_operator { - template static meta_yes testFunctor(C const *,typename enable_if<(sizeof(return_ref().operator()(Index(0)))>0)>::type * = 0); + template static meta_yes testFunctor(C const *,typename enable_if<(sizeof(return_ref().operator()(IndexType(0)))>0)>::type * = 0); static meta_no testFunctor(...); enum { value = sizeof(testFunctor(static_cast(0))) == sizeof(meta_yes) }; }; -template +template struct has_binary_operator { - template static meta_yes testFunctor(C const *,typename enable_if<(sizeof(return_ref().operator()(Index(0),Index(0)))>0)>::type * = 0); + template static meta_yes testFunctor(C const *,typename enable_if<(sizeof(return_ref().operator()(IndexType(0),IndexType(0)))>0)>::type * = 0); static meta_no testFunctor(...); enum { value = sizeof(testFunctor(static_cast(0))) == sizeof(meta_yes) }; diff --git a/test/nullary.cpp b/test/nullary.cpp index ad306c1e9..a3c8b991e 100644 --- a/test/nullary.cpp +++ b/test/nullary.cpp @@ -170,5 +170,19 @@ void test_nullary() VERIFY(( internal::has_unary_operator >::value )); VERIFY(( !internal::has_binary_operator >::value )); VERIFY(( internal::functor_has_linear_access >::ret )); + + // Regression unit test for a weird MSVC 2012 bug. + // Search "nullary_wrapper_workaround_msvc_2012" in CoreEvaluators.h for the details. + { + MatrixXf A = MatrixXf::Random(3,3); + Ref R = 2.0*A; + VERIFY_IS_APPROX(R, A+A); + + Ref R1 = MatrixXf::Random(3,3)+A; + + VectorXi V = VectorXi::Random(3); + Ref R2 = VectorXi::LinSpaced(3,1,3)+V; + VERIFY_IS_APPROX(R2, V+Vector3i(1,2,3)); + } #endif } -- cgit v1.2.3 From b046a3f87d90d0f815dc03b9fdfcb1fda32504fb Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 6 Sep 2016 15:47:04 +0200 Subject: Workaround MSVC instantiation faillure of has_*ary_operator at the level of triats::match so that the has_*ary_operator are really properly instantiated throughout the compilation unit. --- Eigen/src/Core/CoreEvaluators.h | 34 +++++++++++++++++----------------- Eigen/src/Core/Ref.h | 8 +++++++- test/nullary.cpp | 15 +++++++++++++-- 3 files changed, 37 insertions(+), 20 deletions(-) (limited to 'test/nullary.cpp') diff --git a/Eigen/src/Core/CoreEvaluators.h b/Eigen/src/Core/CoreEvaluators.h index c5ad37847..ece8c0fcf 100644 --- a/Eigen/src/Core/CoreEvaluators.h +++ b/Eigen/src/Core/CoreEvaluators.h @@ -393,9 +393,9 @@ struct nullary_wrapper template struct nullary_wrapper {}; -#if EIGEN_COMP_MSVC>0 && EIGEN_COMP_MSVC<=1700 +#if EIGEN_COMP_MSVC>0 -// MSVC 2012 (and probably older ones too) exhibits a weird compilation error when +// MSVC exhibits a weird compilation error when // compiling: // Eigen::MatrixXf A = MatrixXf::Random(3,3); // Ref R = 2.f*A; @@ -408,8 +408,8 @@ struct nullary_wrapper {}; // This is a simple wrapper around Index to enforce the re-instantiation of // has_*ary_operator when needed. -template struct nullary_wrapper_workaround_msvc_2012 { - nullary_wrapper_workaround_msvc_2012(const T&); +template struct nullary_wrapper_workaround_msvc { + nullary_wrapper_workaround_msvc(const T&); operator T()const; }; @@ -419,34 +419,34 @@ struct nullary_wrapper template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { return nullary_wrapper >::value, - has_unary_operator >::value, - has_binary_operator >::value>().operator()(op,i,j); + has_nullary_operator >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i,j); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return nullary_wrapper >::value, - has_unary_operator >::value, - has_binary_operator >::value>().operator()(op,i); + has_nullary_operator >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { return nullary_wrapper >::value, - has_unary_operator >::value, - has_binary_operator >::value>().template packetOp(op,i,j); + has_nullary_operator >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i,j); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return nullary_wrapper >::value, - has_unary_operator >::value, - has_binary_operator >::value>().template packetOp(op,i); + has_nullary_operator >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i); } }; -#endif // MSVC<=2012 workaround +#endif // MSVC workaround template struct evaluator > diff --git a/Eigen/src/Core/Ref.h b/Eigen/src/Core/Ref.h index 17065fdd5..bdf24f52a 100644 --- a/Eigen/src/Core/Ref.h +++ b/Eigen/src/Core/Ref.h @@ -35,7 +35,13 @@ struct traits > || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), OuterStrideMatch = Derived::IsVectorAtCompileTime || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), - AlignmentMatch = (int(traits::Alignment)==int(Unaligned)) || (int(evaluator::Alignment) >= int(Alignment)), // FIXME the first condition is not very clear, it should be replaced by the required alignment + // NOTE, this indirection of evaluator::Alignment is needed + // to workaround a very strange bug in MSVC related to the instantiation + // of has_*ary_operator in evaluator. + // This line is surprisingly very sensitive. For instance, simply adding parenthesis + // as "DerivedAlignment = (int(evaluator::Alignment))," will make MSVC fail... + DerivedAlignment = int(evaluator::Alignment), + AlignmentMatch = (int(traits::Alignment)==int(Unaligned)) || (DerivedAlignment >= int(Alignment)), // FIXME the first condition is not very clear, it should be replaced by the required alignment ScalarTypeMatch = internal::is_same::value, MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch }; diff --git a/test/nullary.cpp b/test/nullary.cpp index a3c8b991e..9063c6de8 100644 --- a/test/nullary.cpp +++ b/test/nullary.cpp @@ -171,8 +171,9 @@ void test_nullary() VERIFY(( !internal::has_binary_operator >::value )); VERIFY(( internal::functor_has_linear_access >::ret )); - // Regression unit test for a weird MSVC 2012 bug. - // Search "nullary_wrapper_workaround_msvc_2012" in CoreEvaluators.h for the details. + // Regression unit test for a weird MSVC bug. + // Search "nullary_wrapper_workaround_msvc" in CoreEvaluators.h for the details. + // See also traits::match. { MatrixXf A = MatrixXf::Random(3,3); Ref R = 2.0*A; @@ -183,6 +184,16 @@ void test_nullary() VectorXi V = VectorXi::Random(3); Ref R2 = VectorXi::LinSpaced(3,1,3)+V; VERIFY_IS_APPROX(R2, V+Vector3i(1,2,3)); + + VERIFY(( internal::has_nullary_operator >::value )); + VERIFY(( !internal::has_unary_operator >::value )); + VERIFY(( !internal::has_binary_operator >::value )); + VERIFY(( internal::functor_has_linear_access >::ret )); + + VERIFY(( !internal::has_nullary_operator >::value )); + VERIFY(( internal::has_unary_operator >::value )); + VERIFY(( !internal::has_binary_operator >::value )); + VERIFY(( internal::functor_has_linear_access >::ret )); } #endif } -- cgit v1.2.3