libstdc++: Add additional overload of std::lerp [PR101870]
The [cmath.syn] p1 wording about additional overloads sufficient to handle any arithmetic types also applies to std::lerp. This adds a new overload of std::lerp that does the required promotions to support arguments of arbitrary arithmetic types. A new __promoted_t alias template is added, which the C++17 function templates std::hypot and std::lerp can use to avoid instantiating the __promote_3 class template. Signed-off-by: Jonathan Wakely <jwakely@redhat.com> libstdc++-v3/ChangeLog: PR libstdc++/101870 * include/c_global/cmath (hypot): Use __promoted_t. (lerp): Add new overload accepting any arithmetic types. * include/ext/type_traits.h (__promoted_t): New alias template. * testsuite/26_numerics/lerp.cc: Moved to... * testsuite/26_numerics/lerp/1.cc: ...here. * testsuite/26_numerics/lerp/constexpr.cc: New test. * testsuite/26_numerics/lerp/version.cc: New test.
This commit is contained in:
parent
b1c0e8599a
commit
9017326e19
|
@ -1844,7 +1844,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif // _GLIBCXX_USE_C99_MATH_TR1
|
||||
#endif // C++11
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
#if __cplusplus >= 201703L
|
||||
|
||||
// [c.math.hypot3], three-dimensional hypotenuse
|
||||
#define __cpp_lib_hypot 201603
|
||||
|
@ -1877,15 +1877,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ return std::__hypot3<long double>(__x, __y, __z); }
|
||||
|
||||
template<typename _Tp, typename _Up, typename _Vp>
|
||||
typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type
|
||||
__gnu_cxx::__promoted_t<_Tp, _Up, _Vp>
|
||||
hypot(_Tp __x, _Up __y, _Vp __z)
|
||||
{
|
||||
using __type = typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type;
|
||||
using __type = __gnu_cxx::__promoted_t<_Tp, _Up, _Vp>;
|
||||
return std::__hypot3<__type>(__x, __y, __z);
|
||||
}
|
||||
#endif // C++17
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
#if __cplusplus >= 202002L
|
||||
// linear interpolation
|
||||
# define __cpp_lib_interpolate 201902L
|
||||
|
||||
|
@ -1918,6 +1918,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
constexpr long double
|
||||
lerp(long double __a, long double __b, long double __t) noexcept
|
||||
{ return std::__lerp(__a, __b, __t); }
|
||||
|
||||
template<typename _Tp, typename _Up, typename _Vp>
|
||||
constexpr __gnu_cxx::__promoted_t<_Tp, _Up, _Vp>
|
||||
lerp(_Tp __x, _Up __y, _Vp __z) noexcept
|
||||
{
|
||||
using __type = __gnu_cxx::__promoted_t<_Tp, _Up, _Vp>;
|
||||
return std::__lerp<__type>(__x, __y, __z);
|
||||
}
|
||||
#endif // C++20
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
|
|
|
@ -163,7 +163,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ return true; }
|
||||
#endif
|
||||
|
||||
// For complex and cmath
|
||||
// For arithmetic promotions in <complex> and <cmath>
|
||||
|
||||
template<typename _Tp, bool = std::__is_integer<_Tp>::__value>
|
||||
struct __promote
|
||||
{ typedef double __type; };
|
||||
|
@ -187,6 +188,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct __promote<float>
|
||||
{ typedef float __type; };
|
||||
|
||||
#if __cpp_fold_expressions
|
||||
template<typename... _Tp>
|
||||
using __promoted_t = decltype((typename __promote<_Tp>::__type(0) + ...));
|
||||
#endif
|
||||
|
||||
template<typename _Tp, typename _Up,
|
||||
typename _Tp2 = typename __promote<_Tp>::__type,
|
||||
typename _Up2 = typename __promote<_Up>::__type>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <cmath>
|
||||
|
||||
// Fails template argument deduction unless both arguments are the same type.
|
||||
template<typename T>
|
||||
constexpr bool
|
||||
eq(T result, T expected) { return result == expected; }
|
||||
|
||||
static_assert( eq( std::lerp(-10.0, 10.0, 0.25), -5.0 ) );
|
||||
static_assert( eq( std::lerp(2.0f, 2.0f, 200.0f), 2.0f ) );
|
||||
static_assert( eq( std::lerp(2.0L, 4.0L, 200.0L), 402.0L ) );
|
||||
// at least one type is long double, so result is long double
|
||||
static_assert( eq( std::lerp(2.0L, 4.0f, -20.0), -38.0L ) );
|
||||
// at least one type is double, so result is double:
|
||||
static_assert( eq( std::lerp(-8.0f, 10.0, 0.5f), 1.0 ) );
|
||||
// int promotes to double, so result is double
|
||||
static_assert( eq( std::lerp(0, 1, 0), 0.0 ) );
|
||||
// int promotes to double, so result is double
|
||||
static_assert( eq( std::lerp(2.0f, -10.0f, 1), -10.0 ) );
|
|
@ -0,0 +1,10 @@
|
|||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do preprocess { target c++2a } }
|
||||
|
||||
#include <version>
|
||||
|
||||
#ifndef __cpp_lib_interpolate
|
||||
# error "Feature-test macro for midpoint and lerp missing in <version>"
|
||||
#elif __cpp_lib_interpolate != 201902L
|
||||
# error "Feature-test macro for midpoint and lerp has wrong value in <version>"
|
||||
#endif
|
Loading…
Reference in New Issue