From cd577a275c3420d743a044e37484ab8fd1e17e37 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 24 Jun 2016 11:28:54 +0200 Subject: [PATCH] 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>. This patch also defers calls to NumTraits in cases for which types are not directly compatible. --- Eigen/src/Core/util/XprHelper.h | 46 ++++++++++++++++++++++++--------- 1 file 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::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::Literal is returned if T is implicitly convertible to NumTraits::Literal AND that this does not imply a float to integer conversion. +// - otherwise, NumTraits::Literal is returned if T is implicitly convertible to NumTraits::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::Literal>::value, - bool IsSafe = NumTraits::IsInteger || !NumTraits::Literal>::IsInteger> -struct promote_scalar_arg -{ -}; +template +struct promote_scalar_arg; -template -struct promote_scalar_arg +template +struct promote_scalar_arg { typedef T type; }; +// Recursively check safe conversion to PromotedType, and then ExprScalar if they are different. +template::value, + bool IsSafe = NumTraits::IsInteger || !NumTraits::IsInteger> +struct promote_scalar_arg_unsupported; + +// Start recursion with NumTraits::Literal template -struct promote_scalar_arg +struct promote_scalar_arg : promote_scalar_arg_unsupported::Literal> {}; + +// We found a match! +template +struct promote_scalar_arg_unsupported { - typedef typename NumTraits::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 +struct promote_scalar_arg_unsupported + : promote_scalar_arg_unsupported +{}; + +// Unsafe real-to-integer, let's stop. +template +struct promote_scalar_arg_unsupported {}; + +// T is not even convertible to ExprScalar, let's stop. +template +struct promote_scalar_arg_unsupported {}; + //classes inheriting no_assignment_operator don't generate a default operator=. class no_assignment_operator {