Fix Random().normalized() by introducing a nested_eval helper (recall that the old nested<> class is deprecated)

This commit is contained in:
Gael Guennebaud 2014-01-26 15:35:44 +01:00
parent 34694d8828
commit 94acccc126
2 changed files with 35 additions and 1 deletions

View File

@ -141,8 +141,13 @@ template<typename Derived>
inline const typename MatrixBase<Derived>::PlainObject inline const typename MatrixBase<Derived>::PlainObject
MatrixBase<Derived>::normalized() const MatrixBase<Derived>::normalized() const
{ {
typedef typename internal::nested<Derived>::type Nested; #ifndef EIGEN_TEST_EVALUATORS
typedef typename internal::nested<Derived,2>::type Nested;
typedef typename internal::remove_reference<Nested>::type _Nested; typedef typename internal::remove_reference<Nested>::type _Nested;
#else
typedef typename internal::nested_eval<Derived,2>::type _Nested;
// typedef typename internal::remove_reference<Nested>::type _Nested;
#endif // EIGEN_TEST_EVALUATORS
_Nested n(derived()); _Nested n(derived());
return n / n.norm(); return n / n.norm();
} }

View File

@ -296,11 +296,40 @@ struct transfer_constness
#ifdef EIGEN_TEST_EVALUATORS #ifdef EIGEN_TEST_EVALUATORS
// When using evaluators, we never evaluate when assembling the expression!! // When using evaluators, we never evaluate when assembling the expression!!
// TODO: get rid of this nested class since it's just an alias for ref_selector.
template<typename T, int n=1, typename PlainObject = typename eval<T>::type> struct nested template<typename T, int n=1, typename PlainObject = typename eval<T>::type> struct nested
{ {
typedef typename ref_selector<T>::type type; typedef typename ref_selector<T>::type type;
}; };
// However, we still need a mechanism to detect whether an expression which is evaluated multiple time
// has to be evaluated into a temporary.
// That's the purpose of this new nested_eval helper:
template<typename T, int n, typename PlainObject = typename eval<T>::type> struct nested_eval
{
enum {
// For the purpose of this test, to keep it reasonably simple, we arbitrarily choose a value of Dynamic values.
// the choice of 10000 makes it larger than any practical fixed value and even most dynamic values.
// in extreme cases where these assumptions would be wrong, we would still at worst suffer performance issues
// (poor choice of temporaries).
// It's important that this value can still be squared without integer overflowing.
DynamicAsInteger = 10000,
ScalarReadCost = NumTraits<typename traits<T>::Scalar>::ReadCost,
ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost),
CoeffReadCost = traits<T>::CoeffReadCost,
CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost),
NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n,
CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger,
CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger
};
typedef typename conditional<
int(CostEvalAsInteger) < int(CostNoEvalAsInteger),
PlainObject,
typename ref_selector<T>::type
>::type type;
};
#else #else
/** \internal Determines how a given expression should be nested into another one. /** \internal Determines how a given expression should be nested into another one.
* For example, when you do a * (b+c), Eigen will determine how the expression b+c should be * For example, when you do a * (b+c), Eigen will determine how the expression b+c should be