Hi mclow.lists, EricWF,
This patch enables generic <cmath> overloads for types unambiguously
convertible to any arithmetic type. Addresses PR18218.
Only `pow` is implemented completely, with proper `noexcept` specifications and
the conversion dance, taken from Howard's original patch. If it looks good I'll
extend the implementation and test cases to all the other generic <cmath>
overloads.
http://reviews.llvm.org/D5942
Files:
include/cmath
include/type_traits
test/numerics/c.math/cmath.pass.cpp
Index: include/cmath
===================================================================
--- include/cmath
+++ include/cmath
@@ -325,7 +325,7 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<std::__promote<_A1>::value, bool>::type
signbit(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_signbit((typename std::__promote<_A1>::type)__lcpp_x);
@@ -349,7 +349,7 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, int>::type
+typename std::enable_if<std::__promote<_A1>::value, int>::type
fpclassify(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_fpclassify((typename std::__promote<_A1>::type)__lcpp_x);
@@ -373,7 +373,7 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<std::__promote<_A1>::value, bool>::type
isfinite(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isfinite((typename std::__promote<_A1>::type)__lcpp_x);
@@ -397,7 +397,7 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<std::__promote<_A1>::value, bool>::type
isinf(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isinf((typename std::__promote<_A1>::type)__lcpp_x);
@@ -421,7 +421,7 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<std::__promote<_A1>::value, bool>::type
isnan(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isnan((typename std::__promote<_A1>::type)__lcpp_x);
@@ -445,7 +445,7 @@
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
+typename std::enable_if<std::__promote<_A1>::value, bool>::type
isnormal(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isnormal((typename std::__promote<_A1>::type)__lcpp_x);
@@ -471,8 +471,7 @@
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if
<
- std::is_arithmetic<_A1>::value &&
- std::is_arithmetic<_A2>::value,
+ std::__promote<_A1, _A2>::value,
bool
>::type
isgreater(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
@@ -501,8 +500,7 @@
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if
<
- std::is_arithmetic<_A1>::value &&
- std::is_arithmetic<_A2>::value,
+ std::__promote<_A1, _A2>::value,
bool
>::type
isgreaterequal(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
@@ -531,8 +529,7 @@
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if
<
- std::is_arithmetic<_A1>::value &&
- std::is_arithmetic<_A2>::value,
+ std::__promote<_A1, _A2>::value,
bool
>::type
isless(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
@@ -561,8 +558,7 @@
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if
<
- std::is_arithmetic<_A1>::value &&
- std::is_arithmetic<_A2>::value,
+ std::__promote<_A1, _A2>::value,
bool
>::type
islessequal(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
@@ -591,8 +587,7 @@
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if
<
- std::is_arithmetic<_A1>::value &&
- std::is_arithmetic<_A2>::value,
+ std::__promote<_A1, _A2>::value,
bool
>::type
islessgreater(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
@@ -621,8 +616,7 @@
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if
<
- std::is_arithmetic<_A1>::value &&
- std::is_arithmetic<_A2>::value,
+ std::__promote<_A1, _A2>::value,
bool
>::type
isunordered(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
@@ -727,12 +721,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
atan2(_A1 __lcpp_y, _A2 __lcpp_x) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
@@ -849,12 +838,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
fmod(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
@@ -952,18 +936,25 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
-pow(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
+typename __promote<_A1, _A2>::type
+#ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+pow(_A1 __lcpp_x, _A2 __lcpp_y)
+#else
+pow(_A1&& __lcpp_x, _A2&& __lcpp_y)
+ _NOEXCEPT_
+ (
+ _NOEXCEPT_(__promote<_A1>::__does_not_throw) &&
+ _NOEXCEPT_(__promote<_A2>::__does_not_throw)
+ )
+#endif
{
- typedef typename __promote<_A1, _A2>::type __result_type;
- static_assert((!(is_same<_A1, __result_type>::value &&
- is_same<_A2, __result_type>::value)), "");
- return pow((__result_type)__lcpp_x, (__result_type)__lcpp_y);
+ typedef typename __promote<_A1>::type _D1;
+ typedef typename __promote<_A2>::type _D2;
+ typedef typename __promote<_D1, _D2>::type type;
+ static_assert((!(is_same<typename remove_reference<_A1>::type, type>::value &&
+ is_same<typename remove_reference<_A2>::type, type>::value)), "");
+ return pow(static_cast<type>(static_cast<_D1>(_VSTD::forward<_A1>(__lcpp_x))),
+ static_cast<type>(static_cast<_D2>(_VSTD::forward<_A2>(__lcpp_y))));
}
// sin
@@ -1114,12 +1105,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
copysign(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
@@ -1192,12 +1178,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
fdim(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
@@ -1216,13 +1197,7 @@
template <class _A1, class _A2, class _A3>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value &&
- is_arithmetic<_A3>::value,
- __promote<_A1, _A2, _A3>
->::type
+typename __promote<_A1, _A2, _A3>::type
fma(_A1 __lcpp_x, _A2 __lcpp_y, _A3 __lcpp_z) _NOEXCEPT
{
typedef typename __promote<_A1, _A2, _A3>::type __result_type;
@@ -1242,12 +1217,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
fmax(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
@@ -1266,12 +1236,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
fmin(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
@@ -1290,12 +1255,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
hypot(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
@@ -1459,12 +1419,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
nextafter(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
@@ -1496,12 +1451,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
remainder(_A1 __lcpp_x, _A2 __lcpp_y) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
@@ -1520,12 +1470,7 @@
template <class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-typename __lazy_enable_if
-<
- is_arithmetic<_A1>::value &&
- is_arithmetic<_A2>::value,
- __promote<_A1, _A2>
->::type
+typename __promote<_A1, _A2>::type
remquo(_A1 __lcpp_x, _A2 __lcpp_y, int* __lcpp_z) _NOEXCEPT
{
typedef typename __promote<_A1, _A2>::type __result_type;
Index: include/type_traits
===================================================================
--- include/type_traits
+++ include/type_traits
@@ -218,9 +218,6 @@
template <bool _Bp, class _If, class _Then> using conditional_t = typename conditional<_Bp, _If, _Then>::type;
#endif
-template <bool, class _Tp> struct _LIBCPP_TYPE_VIS_ONLY __lazy_enable_if {};
-template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY __lazy_enable_if<true, _Tp> {typedef typename _Tp::type type;};
-
template <bool, class _Tp = void> struct _LIBCPP_TYPE_VIS_ONLY enable_if {};
template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY enable_if<true, _Tp> {typedef _Tp type;};
@@ -1180,29 +1177,34 @@
#endif // _LIBCPP_HAS_NO_VARIADICS
-template <class _Tp>
+float __numeric_test(float);
+double __numeric_test(char);
+double __numeric_test(int);
+double __numeric_test(unsigned);
+double __numeric_test(long);
+double __numeric_test(unsigned long);
+double __numeric_test(long long);
+double __numeric_test(unsigned long long);
+double __numeric_test(double);
+long double __numeric_test(long double);
+
+template <class _Tp, class = void>
struct __numeric_type
{
- static void __test(...);
- static float __test(float);
- static double __test(char);
- static double __test(int);
- static double __test(unsigned);
- static double __test(long);
- static double __test(unsigned long);
- static double __test(long long);
- static double __test(unsigned long long);
- static double __test(double);
- static long double __test(long double);
+ static const bool value = false;
+};
- typedef decltype(__test(declval<_Tp>())) type;
- static const bool value = !is_same<type, void>::value;
+template <class _Tp>
+struct __numeric_type<_Tp, decltype(__numeric_test(declval<_Tp>()), void())>
+{
+ typedef decltype(__numeric_test(declval<_Tp>())) type;
+ static const bool value = true;
};
template <>
struct __numeric_type<void>
{
- static const bool value = true;
+ static const bool value = true;
};
// __promote
@@ -1241,11 +1243,12 @@
};
template <class _A1>
-class __promote_imp<_A1, void, void, true>
+struct __promote_imp<_A1, void, void, true>
{
public:
typedef typename __numeric_type<_A1>::type type;
static const bool value = true;
+ static const bool __does_not_throw = _NOEXCEPT_OR_FALSE(static_cast<type>(declval<_A1>()));
};
template <class _A1, class _A2 = void, class _A3 = void>
Index: test/numerics/c.math/cmath.pass.cpp
===================================================================
--- test/numerics/c.math/cmath.pass.cpp
+++ test/numerics/c.math/cmath.pass.cpp
@@ -435,15 +435,15 @@
static_assert((std::is_same<decltype(std::powf(0,0)), float>::value), "");
static_assert((std::is_same<decltype(std::powl(0,0)), long double>::value), "");
static_assert((std::is_same<decltype(std::pow((int)0, (int)0)), double>::value), "");
-// static_assert((std::is_same<decltype(std::pow(Value<int>(), (int)0)), double>::value), "");
-// static_assert((std::is_same<decltype(std::pow(Value<long double>(), (float)0)), long double>::value), "");
-// static_assert((std::is_same<decltype(std::pow((float) 0, Value<float>())), float>::value), "");
+ static_assert((std::is_same<decltype(std::pow(Value<int>(), (int)0)), double>::value), "");
+ static_assert((std::is_same<decltype(std::pow(Value<long double>(), (float)0)), long double>::value), "");
+ static_assert((std::is_same<decltype(std::pow((float) 0, Value<float>())), float>::value), "");
static_assert((std::is_same<decltype(pow(Ambiguous(), Ambiguous())), Ambiguous>::value), "");
assert(std::pow(1,1) == 1);
-// assert(std::pow(Value<int,1>(), Value<float,1>()) == 1);
-// assert(std::pow(1.0f, Value<double,1>()) == 1);
-// assert(std::pow(1.0, Value<int,1>()) == 1);
-// assert(std::pow(Value<long double,1>(), 1LL) == 1);
+ assert(std::pow(Value<int,1>(), Value<float,1>()) == 1);
+ assert(std::pow(1.0f, Value<double,1>()) == 1);
+ assert(std::pow(1.0, Value<int,1>()) == 1);
+ assert(std::pow(Value<long double,1>(), 1LL) == 1);
}
void test_sin()
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits