aboutsummaryrefslogtreecommitdiffhomepage
path: root/Eigen/src/Core/util/XprHelper.h
diff options
context:
space:
mode:
authorGravatar Gael Guennebaud <g.gael@free.fr>2016-06-24 11:28:54 +0200
committerGravatar Gael Guennebaud <g.gael@free.fr>2016-06-24 11:28:54 +0200
commitcd577a275c3420d743a044e37484ab8fd1e17e37 (patch)
treec45b350c121c87a0c14ce6a141399e5cb352af98 /Eigen/src/Core/util/XprHelper.h
parentdeb45ad4bc5542b7c66cfb3b465ac106294c3ddd (diff)
Relax promote_scalar_arg logic to enable promotion to Expr::Scalar if conversion to Expr::Literal fails.
This is useful to cancel expression template at the scalar level, e.g. with AutoDiff<AutoDiff<>>. This patch also defers calls to NumTraits in cases for which types are not directly compatible.
Diffstat (limited to 'Eigen/src/Core/util/XprHelper.h')
-rw-r--r--Eigen/src/Core/util/XprHelper.h46
1 files changed, 34 insertions, 12 deletions
diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h
index b372ac1ad..3e8048d27 100644
--- a/Eigen/src/Core/util/XprHelper.h
+++ b/Eigen/src/Core/util/XprHelper.h
@@ -51,28 +51,50 @@ inline IndexDest convert_index(const IndexSrc& idx) {
// The IsSupported template parameter must be provided by the caller as: ScalarBinaryOpTraits<ExprScalar,T,op>::Defined using the proper order for ExprScalar and T.
// Then the logic is as follows:
// - if the operation is natively supported as defined by IsSupported, then the scalar type is not promoted, and T is returned.
-// - otherwise, NumTraits<T>::Literal is returned if T is implicitly convertible to NumTraits<T>::Literal AND that this does not imply a float to integer conversion.
+// - otherwise, NumTraits<ExprScalar>::Literal is returned if T is implicitly convertible to NumTraits<ExprScalar>::Literal AND that this does not imply a float to integer conversion.
+// - otherwise, ExprScalar is returned if T is implicitly convertible to ExprScalar AND that this does not imply a float to integer conversion.
// - In all other cases, the promoted type is not defined, and the respective operation is thus invalid and not available (SFINAE).
-template<typename ExprScalar,typename T,
- bool IsSupported,
- bool ConvertibleToLiteral = internal::is_convertible<T,typename NumTraits<ExprScalar>::Literal>::value,
- bool IsSafe = NumTraits<T>::IsInteger || !NumTraits<typename NumTraits<ExprScalar>::Literal>::IsInteger>
-struct promote_scalar_arg
-{
-};
+template<typename ExprScalar,typename T, bool IsSupported>
+struct promote_scalar_arg;
-template<typename S,typename T, bool ConvertibleToLiteral, bool IsSafe>
-struct promote_scalar_arg<S,T,true,ConvertibleToLiteral,IsSafe>
+template<typename S,typename T>
+struct promote_scalar_arg<S,T,true>
{
typedef T type;
};
+// Recursively check safe conversion to PromotedType, and then ExprScalar if they are different.
+template<typename ExprScalar,typename T,typename PromotedType,
+ bool ConvertibleToLiteral = internal::is_convertible<T,PromotedType>::value,
+ bool IsSafe = NumTraits<T>::IsInteger || !NumTraits<PromotedType>::IsInteger>
+struct promote_scalar_arg_unsupported;
+
+// Start recursion with NumTraits<ExprScalar>::Literal
template<typename S,typename T>
-struct promote_scalar_arg<S,T,false,true,true>
+struct promote_scalar_arg<S,T,false> : promote_scalar_arg_unsupported<S,T,typename NumTraits<S>::Literal> {};
+
+// We found a match!
+template<typename S,typename T, typename PromotedType>
+struct promote_scalar_arg_unsupported<S,T,PromotedType,true,true>
{
- typedef typename NumTraits<S>::Literal type;
+ typedef PromotedType type;
};
+// No match, but no real-to-integer issues, and ExprScalar and current PromotedType are different,
+// so let's try to promote to ExprScalar
+template<typename ExprScalar,typename T, typename PromotedType>
+struct promote_scalar_arg_unsupported<ExprScalar,T,PromotedType,false,true>
+ : promote_scalar_arg_unsupported<ExprScalar,T,ExprScalar>
+{};
+
+// Unsafe real-to-integer, let's stop.
+template<typename S,typename T, typename PromotedType>
+struct promote_scalar_arg_unsupported<S,T,PromotedType,false,false> {};
+
+// T is not even convertible to ExprScalar, let's stop.
+template<typename S,typename T>
+struct promote_scalar_arg_unsupported<S,T,S,false,true> {};
+
//classes inheriting no_assignment_operator don't generate a default operator=.
class no_assignment_operator
{