Add explicit conversion operators and tests to expression templates.

This commit is contained in:
jzmaddock
2015-03-12 17:55:13 +00:00
parent 51a320e98a
commit f4a61d5f47
2 changed files with 190 additions and 7 deletions

View File

@@ -360,11 +360,36 @@ struct expression<tag, Arg1, void, void, void>
static const unsigned depth = left_type::depth + 1;
#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
explicit operator bool()const
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
//
// Horrible workaround for gcc-4.6.x which always prefers the template
// operator bool() rather than the non-template operator when converting to
// an arithmetic type:
//
template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
explicit operator T ()const
{
result_type r(*this);
return static_cast<bool>(r);
}
template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
explicit operator T ()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
BOOST_MP_FORCEINLINE explicit operator bool()const
{
result_type r(*this);
return static_cast<bool>(r);
}
explicit operator void()const {}
# endif
#else
operator unmentionable_type()const
{
@@ -373,6 +398,13 @@ struct expression<tag, Arg1, void, void, void>
}
#endif
template <class T>
T convert_to()
{
result_type r(*this);
return r.template convert_to<T>();
}
private:
typename expression_storage<Arg1>::type arg;
expression& operator=(const expression&);
@@ -392,10 +424,36 @@ struct expression<terminal, Arg1, void, void, void>
static const unsigned depth = 0;
#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
explicit operator bool()const
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
//
// Horrible workaround for gcc-4.6.x which always prefers the template
// operator bool() rather than the non-template operator when converting to
// an arithmetic type:
//
template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
explicit operator T ()const
{
return static_cast<bool>(arg);
result_type r(*this);
return static_cast<bool>(r);
}
template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
explicit operator T ()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
BOOST_MP_FORCEINLINE explicit operator bool()const
{
result_type r(*this);
return static_cast<bool>(r);
}
explicit operator void()const {}
# endif
#else
operator unmentionable_type()const
{
@@ -403,6 +461,13 @@ struct expression<terminal, Arg1, void, void, void>
}
#endif
template <class T>
T convert_to()
{
result_type r(*this);
return r.template convert_to<T>();
}
private:
typename expression_storage<Arg1>::type arg;
expression& operator=(const expression&);
@@ -427,11 +492,36 @@ struct expression<tag, Arg1, Arg2, void, void>
const Arg2& right_ref()const BOOST_NOEXCEPT { return arg2; }
#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
explicit operator bool()const
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
//
// Horrible workaround for gcc-4.6.x which always prefers the template
// operator bool() rather than the non-template operator when converting to
// an arithmetic type:
//
template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
explicit operator T ()const
{
result_type r(*this);
return static_cast<bool>(r);
}
template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
explicit operator T ()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
BOOST_MP_FORCEINLINE explicit operator bool()const
{
result_type r(*this);
return static_cast<bool>(r);
}
explicit operator void()const {}
# endif
#else
operator unmentionable_type()const
{
@@ -439,6 +529,13 @@ struct expression<tag, Arg1, Arg2, void, void>
return r ? &unmentionable::proc : 0;
}
#endif
template <class T>
T convert_to()
{
result_type r(*this);
return r.template convert_to<T>();
}
static const unsigned left_depth = left_type::depth + 1;
static const unsigned right_depth = right_type::depth + 1;
static const unsigned depth = left_depth > right_depth ? left_depth : right_depth;
@@ -474,11 +571,36 @@ struct expression<tag, Arg1, Arg2, Arg3, void>
const Arg3& right_ref()const BOOST_NOEXCEPT { return arg3; }
#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
explicit operator bool()const
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
//
// Horrible workaround for gcc-4.6.x which always prefers the template
// operator bool() rather than the non-template operator when converting to
// an arithmetic type:
//
template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
explicit operator T ()const
{
result_type r(*this);
return static_cast<bool>(r);
}
template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
explicit operator T ()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
BOOST_MP_FORCEINLINE explicit operator bool()const
{
result_type r(*this);
return static_cast<bool>(r);
}
explicit operator void()const {}
# endif
#else
operator unmentionable_type()const
{
@@ -486,6 +608,13 @@ struct expression<tag, Arg1, Arg2, Arg3, void>
return r ? &unmentionable::proc : 0;
}
#endif
template <class T>
T convert_to()
{
result_type r(*this);
return r.template convert_to<T>();
}
static const unsigned left_depth = left_type::depth + 1;
static const unsigned middle_depth = middle_type::depth + 1;
static const unsigned right_depth = right_type::depth + 1;
@@ -530,11 +659,36 @@ struct expression
const Arg4& right_ref()const BOOST_NOEXCEPT { return arg4; }
#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
explicit operator bool()const
# if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) || (defined(BOOST_INTEL) && (BOOST_INTEL <= 1500))
//
// Horrible workaround for gcc-4.6.x which always prefers the template
// operator bool() rather than the non-template operator when converting to
// an arithmetic type:
//
template <class T, typename boost::enable_if<is_same<T, bool>, int>::type = 0>
explicit operator T ()const
{
result_type r(*this);
return static_cast<bool>(r);
}
template <class T, typename boost::disable_if_c<is_same<T, bool>::value || is_void<T>::value || is_number<T>::value, int>::type = 0>
explicit operator T ()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
# else
template <class T, typename boost::disable_if_c<is_number<T>::value, int>::type = 0>
explicit operator T()const
{
return static_cast<T>(static_cast<result_type>(*this));
}
BOOST_MP_FORCEINLINE explicit operator bool()const
{
result_type r(*this);
return static_cast<bool>(r);
}
explicit operator void()const {}
# endif
#else
operator unmentionable_type()const
{
@@ -542,6 +696,13 @@ struct expression
return r ? &unmentionable::proc : 0;
}
#endif
template <class T>
T convert_to()
{
result_type r(*this);
return r.template convert_to<T>();
}
static const unsigned left_depth = left_type::depth + 1;
static const unsigned left_middle_depth = left_middle_type::depth + 1;
static const unsigned right_middle_depth = right_middle_type::depth + 1;

View File

@@ -958,6 +958,17 @@ void test_negative_mixed(boost::mpl::true_ const&)
BOOST_CHECK_EQUAL(static_cast<Num>(Real(n2)) , n2);
BOOST_CHECK_EQUAL(static_cast<Num>(Real(n3)) , n3);
BOOST_CHECK_EQUAL(static_cast<Num>(Real(n4)) , n4);
#endif
// Conversions when source is an expression template:
BOOST_CHECK_EQUAL((Real(n1) + 0).template convert_to<Num>() , n1);
BOOST_CHECK_EQUAL((Real(n2) + 0).template convert_to<Num>(), n2);
BOOST_CHECK_EQUAL((Real(n3) + 0).template convert_to<Num>(), n3);
BOOST_CHECK_EQUAL((Real(n4) + 0).template convert_to<Num>(), n4);
#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
BOOST_CHECK_EQUAL(static_cast<Num>((Real(n1) + 0)), n1);
BOOST_CHECK_EQUAL(static_cast<Num>((Real(n2) + 0)), n2);
BOOST_CHECK_EQUAL(static_cast<Num>((Real(n3) + 0)), n3);
BOOST_CHECK_EQUAL(static_cast<Num>((Real(n4) + 0)), n4);
#endif
#if defined(TEST_MPFR)
Num tol = 10 * std::numeric_limits<Num>::epsilon();
@@ -1250,7 +1261,18 @@ void test_mixed(const boost::mpl::true_&)
BOOST_CHECK_EQUAL(static_cast<Num>(Real(n3)) , n3);
BOOST_CHECK_EQUAL(static_cast<Num>(Real(n4)) , n4);
#endif
BOOST_CHECK_EQUAL(static_cast<cast_type>(n1) , Real(n1));
// Again with expression templates:
BOOST_CHECK_EQUAL((Real(n1) + 0).template convert_to<Num>(), n1);
BOOST_CHECK_EQUAL((Real(n2) + 0).template convert_to<Num>(), n2);
BOOST_CHECK_EQUAL((Real(n3) + 0).template convert_to<Num>(), n3);
BOOST_CHECK_EQUAL((Real(n4) + 0).template convert_to<Num>(), n4);
#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
BOOST_CHECK_EQUAL(static_cast<Num>(Real(n1) + 0), n1);
BOOST_CHECK_EQUAL(static_cast<Num>(Real(n2) + 0), n2);
BOOST_CHECK_EQUAL(static_cast<Num>(Real(n3) + 0), n3);
BOOST_CHECK_EQUAL(static_cast<Num>(Real(n4) + 0), n4);
#endif
BOOST_CHECK_EQUAL(static_cast<cast_type>(n1), Real(n1));
BOOST_CHECK_EQUAL(static_cast<cast_type>(n2) , Real(n2));
BOOST_CHECK_EQUAL(static_cast<cast_type>(n3) , Real(n3));
BOOST_CHECK_EQUAL(static_cast<cast_type>(n4) , Real(n4));