diff --git a/stl/inc/numbers b/stl/inc/numbers index af5d9e4cec..783399e52c 100644 --- a/stl/inc/numbers +++ b/stl/inc/numbers @@ -14,7 +14,7 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with C+ #ifdef __cpp_lib_concepts #include #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv -#include +#include #endif // ^^^ !defined(__cpp_lib_concepts) ^^^ #pragma pack(push, _CRT_PACKING) @@ -26,10 +26,11 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN namespace numbers { +#ifdef __cpp_lib_concepts template struct _Invalid { static_assert(_Always_false<_Ty>, "A program that instantiates a primary template of a mathematical constant " - "variable template is ill-formed. (N4835 [math.constants]/3)"); + "variable template is ill-formed. (N4944 [math.constants]/3)"); }; _EXPORT_STD template @@ -59,7 +60,6 @@ namespace numbers { _EXPORT_STD template inline constexpr _Ty phi_v = _Invalid<_Ty>{}; -#ifdef __cpp_lib_concepts template inline constexpr _Floating e_v<_Floating> = static_cast<_Floating>(2.718281828459045); template @@ -87,86 +87,42 @@ namespace numbers { template inline constexpr _Floating phi_v<_Floating> = static_cast<_Floating>(1.618033988749895); #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv - template <> - inline constexpr double e_v = 2.718281828459045; - template <> - inline constexpr double log2e_v = 1.4426950408889634; - template <> - inline constexpr double log10e_v = 0.4342944819032518; - template <> - inline constexpr double pi_v = 3.141592653589793; - template <> - inline constexpr double inv_pi_v = 0.3183098861837907; - template <> - inline constexpr double inv_sqrtpi_v = 0.5641895835477563; - template <> - inline constexpr double ln2_v = 0.6931471805599453; - template <> - inline constexpr double ln10_v = 2.302585092994046; - template <> - inline constexpr double sqrt2_v = 1.4142135623730951; - template <> - inline constexpr double sqrt3_v = 1.7320508075688772; - template <> - inline constexpr double inv_sqrt3_v = 0.5773502691896257; - template <> - inline constexpr double egamma_v = 0.5772156649015329; - template <> - inline constexpr double phi_v = 1.618033988749895; + template + struct _Reject_invalid { + static_assert(is_floating_point_v<_Ty>, "A program that instantiates a primary template of a mathematical " + "constant variable template is ill-formed. (N4944 [math.constants]/3)"); + using type = _Ty; + }; - template <> - inline constexpr float e_v = static_cast(e_v); - template <> - inline constexpr float log2e_v = static_cast(log2e_v); - template <> - inline constexpr float log10e_v = static_cast(log10e_v); - template <> - inline constexpr float pi_v = static_cast(pi_v); - template <> - inline constexpr float inv_pi_v = static_cast(inv_pi_v); - template <> - inline constexpr float inv_sqrtpi_v = static_cast(inv_sqrtpi_v); - template <> - inline constexpr float ln2_v = static_cast(ln2_v); - template <> - inline constexpr float ln10_v = static_cast(ln10_v); - template <> - inline constexpr float sqrt2_v = static_cast(sqrt2_v); - template <> - inline constexpr float sqrt3_v = static_cast(sqrt3_v); - template <> - inline constexpr float inv_sqrt3_v = static_cast(inv_sqrt3_v); - template <> - inline constexpr float egamma_v = static_cast(egamma_v); - template <> - inline constexpr float phi_v = static_cast(phi_v); + template + using _Reject_invalid_t = typename _Reject_invalid<_Ty>::type; - template <> - inline constexpr long double e_v = e_v; - template <> - inline constexpr long double log2e_v = log2e_v; - template <> - inline constexpr long double log10e_v = log10e_v; - template <> - inline constexpr long double pi_v = pi_v; - template <> - inline constexpr long double inv_pi_v = inv_pi_v; - template <> - inline constexpr long double inv_sqrtpi_v = inv_sqrtpi_v; - template <> - inline constexpr long double ln2_v = ln2_v; - template <> - inline constexpr long double ln10_v = ln10_v; - template <> - inline constexpr long double sqrt2_v = sqrt2_v; - template <> - inline constexpr long double sqrt3_v = sqrt3_v; - template <> - inline constexpr long double inv_sqrt3_v = inv_sqrt3_v; - template <> - inline constexpr long double egamma_v = egamma_v; - template <> - inline constexpr long double phi_v = phi_v; + _EXPORT_STD template + inline constexpr _Ty e_v = static_cast<_Reject_invalid_t<_Ty>>(2.718281828459045); + _EXPORT_STD template + inline constexpr _Ty log2e_v = static_cast<_Reject_invalid_t<_Ty>>(1.4426950408889634); + _EXPORT_STD template + inline constexpr _Ty log10e_v = static_cast<_Reject_invalid_t<_Ty>>(0.4342944819032518); + _EXPORT_STD template + inline constexpr _Ty pi_v = static_cast<_Reject_invalid_t<_Ty>>(3.141592653589793); + _EXPORT_STD template + inline constexpr _Ty inv_pi_v = static_cast<_Reject_invalid_t<_Ty>>(0.3183098861837907); + _EXPORT_STD template + inline constexpr _Ty inv_sqrtpi_v = static_cast<_Reject_invalid_t<_Ty>>(0.5641895835477563); + _EXPORT_STD template + inline constexpr _Ty ln2_v = static_cast<_Reject_invalid_t<_Ty>>(0.6931471805599453); + _EXPORT_STD template + inline constexpr _Ty ln10_v = static_cast<_Reject_invalid_t<_Ty>>(2.302585092994046); + _EXPORT_STD template + inline constexpr _Ty sqrt2_v = static_cast<_Reject_invalid_t<_Ty>>(1.4142135623730951); + _EXPORT_STD template + inline constexpr _Ty sqrt3_v = static_cast<_Reject_invalid_t<_Ty>>(1.7320508075688772); + _EXPORT_STD template + inline constexpr _Ty inv_sqrt3_v = static_cast<_Reject_invalid_t<_Ty>>(0.5773502691896257); + _EXPORT_STD template + inline constexpr _Ty egamma_v = static_cast<_Reject_invalid_t<_Ty>>(0.5772156649015329); + _EXPORT_STD template + inline constexpr _Ty phi_v = static_cast<_Reject_invalid_t<_Ty>>(1.618033988749895); #endif // ^^^ !defined(__cpp_lib_concepts) ^^^ _EXPORT_STD inline constexpr double e = e_v; diff --git a/tests/std/tests/P0631R8_numbers_math_constants/test.cpp b/tests/std/tests/P0631R8_numbers_math_constants/test.cpp index dfd89fd3b1..fd265a012c 100644 --- a/tests/std/tests/P0631R8_numbers_math_constants/test.cpp +++ b/tests/std/tests/P0631R8_numbers_math_constants/test.cpp @@ -1,18 +1,126 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include +#pragma warning(disable : 4197) // '%s': top-level volatile in cast is ignored + #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) -template +template [[nodiscard]] constexpr bool test_case(T& actual, const U expected) { - STATIC_ASSERT(std::is_same_v); + STATIC_ASSERT(std::is_same_v, const U>); return actual == expected; } -// N4835 [math.constants]/2: "a program may partially or explicitly specialize a mathematical constant +enum class modify_cv { + type_identity, + add_const, + add_volatile, + add_cv, +}; + +template +struct apply_modify_cv { + using type = T; +}; + +template +struct apply_modify_cv { + using type = const T; +}; + +template +struct apply_modify_cv { + using type = volatile T; +}; + +template +struct apply_modify_cv { + using type = const volatile T; +}; + +template +using apply_modify_cv_t = typename apply_modify_cv::type; + +template +constexpr void test_cv_floating_point() { + using F = apply_modify_cv_t; + using D = apply_modify_cv_t; + using L = apply_modify_cv_t; + + assert(test_case(std::numbers::e_v, 0x1.5bf0a8p+1f)); + assert(test_case(std::numbers::e_v, 0x1.5bf0a8b145769p+1)); + assert(test_case(std::numbers::e_v, 0x1.5bf0a8b145769p+1L)); + + assert(test_case(std::numbers::log2e_v, 0x1.715476p+0f)); + assert(test_case(std::numbers::log2e_v, 0x1.71547652b82fep+0)); + assert(test_case(std::numbers::log2e_v, 0x1.71547652b82fep+0L)); + + assert(test_case(std::numbers::log10e_v, 0x1.bcb7b2p-2f)); + assert(test_case(std::numbers::log10e_v, 0x1.bcb7b1526e50ep-2)); + assert(test_case(std::numbers::log10e_v, 0x1.bcb7b1526e50ep-2L)); + + assert(test_case(std::numbers::pi_v, 0x1.921fb6p+1f)); + assert(test_case(std::numbers::pi_v, 0x1.921fb54442d18p+1)); + assert(test_case(std::numbers::pi_v, 0x1.921fb54442d18p+1L)); + + assert(test_case(std::numbers::inv_pi_v, 0x1.45f306p-2f)); + assert(test_case(std::numbers::inv_pi_v, 0x1.45f306dc9c883p-2)); + assert(test_case(std::numbers::inv_pi_v, 0x1.45f306dc9c883p-2L)); + + assert(test_case(std::numbers::inv_sqrtpi_v, 0x1.20dd76p-1f)); + assert(test_case(std::numbers::inv_sqrtpi_v, 0x1.20dd750429b6dp-1)); + assert(test_case(std::numbers::inv_sqrtpi_v, 0x1.20dd750429b6dp-1L)); + + assert(test_case(std::numbers::ln2_v, 0x1.62e430p-1f)); + assert(test_case(std::numbers::ln2_v, 0x1.62e42fefa39efp-1)); + assert(test_case(std::numbers::ln2_v, 0x1.62e42fefa39efp-1L)); + + assert(test_case(std::numbers::ln10_v, 0x1.26bb1cp+1f)); + assert(test_case(std::numbers::ln10_v, 0x1.26bb1bbb55516p+1)); + assert(test_case(std::numbers::ln10_v, 0x1.26bb1bbb55516p+1L)); + + assert(test_case(std::numbers::sqrt2_v, 0x1.6a09e6p+0f)); + assert(test_case(std::numbers::sqrt2_v, 0x1.6a09e667f3bcdp+0)); + assert(test_case(std::numbers::sqrt2_v, 0x1.6a09e667f3bcdp+0L)); + + assert(test_case(std::numbers::sqrt3_v, 0x1.bb67aep+0f)); + assert(test_case(std::numbers::sqrt3_v, 0x1.bb67ae8584caap+0)); + assert(test_case(std::numbers::sqrt3_v, 0x1.bb67ae8584caap+0L)); + + assert(test_case(std::numbers::inv_sqrt3_v, 0x1.279a74p-1f)); + assert(test_case(std::numbers::inv_sqrt3_v, 0x1.279a74590331cp-1)); + assert(test_case(std::numbers::inv_sqrt3_v, 0x1.279a74590331cp-1L)); + + assert(test_case(std::numbers::egamma_v, 0x1.2788d0p-1f)); + assert(test_case(std::numbers::egamma_v, 0x1.2788cfc6fb619p-1)); + assert(test_case(std::numbers::egamma_v, 0x1.2788cfc6fb619p-1L)); + + assert(test_case(std::numbers::phi_v, 0x1.9e377ap+0f)); + assert(test_case(std::numbers::phi_v, 0x1.9e3779b97f4a8p+0)); + assert(test_case(std::numbers::phi_v, 0x1.9e3779b97f4a8p+0L)); +} + +constexpr void test_double() { + assert(test_case(std::numbers::e, 0x1.5bf0a8b145769p+1)); + assert(test_case(std::numbers::log2e, 0x1.71547652b82fep+0)); + assert(test_case(std::numbers::log10e, 0x1.bcb7b1526e50ep-2)); + assert(test_case(std::numbers::pi, 0x1.921fb54442d18p+1)); + assert(test_case(std::numbers::inv_pi, 0x1.45f306dc9c883p-2)); + assert(test_case(std::numbers::inv_sqrtpi, 0x1.20dd750429b6dp-1)); + assert(test_case(std::numbers::ln2, 0x1.62e42fefa39efp-1)); + assert(test_case(std::numbers::ln10, 0x1.26bb1bbb55516p+1)); + assert(test_case(std::numbers::sqrt2, 0x1.6a09e667f3bcdp+0)); + assert(test_case(std::numbers::sqrt3, 0x1.bb67ae8584caap+0)); + assert(test_case(std::numbers::inv_sqrt3, 0x1.279a74590331cp-1)); + assert(test_case(std::numbers::egamma, 0x1.2788cfc6fb619p-1)); + assert(test_case(std::numbers::phi, 0x1.9e3779b97f4a8p+0)); +} + +// N4944 [math.constants]/2: "a program may partially or explicitly specialize a mathematical constant // variable template provided that the specialization depends on a program-defined type." struct Meow { int val; @@ -45,87 +153,38 @@ inline constexpr Meow std::numbers::egamma_v{-120}; template <> inline constexpr Meow std::numbers::phi_v{-130}; +constexpr void test_program_defined_specialization() { + assert(test_case(std::numbers::e_v.val, -10)); + assert(test_case(std::numbers::log2e_v.val, -20)); + assert(test_case(std::numbers::log10e_v.val, -30)); + assert(test_case(std::numbers::pi_v.val, -40)); + assert(test_case(std::numbers::inv_pi_v.val, -50)); + assert(test_case(std::numbers::inv_sqrtpi_v.val, -60)); + assert(test_case(std::numbers::ln2_v.val, -70)); + assert(test_case(std::numbers::ln10_v.val, -80)); + assert(test_case(std::numbers::sqrt2_v.val, -90)); + assert(test_case(std::numbers::sqrt3_v.val, -100)); + assert(test_case(std::numbers::inv_sqrt3_v.val, -110)); + assert(test_case(std::numbers::egamma_v.val, -120)); + assert(test_case(std::numbers::phi_v.val, -130)); +} + +constexpr bool test_all() { + test_cv_floating_point(); + test_cv_floating_point(); + + if (!std::is_constant_evaluated()) { + test_cv_floating_point(); // constexpr-incompatible + test_cv_floating_point(); // constexpr-incompatible + } + + test_double(); + test_program_defined_specialization(); + + return true; +} + int main() { - STATIC_ASSERT(test_case(std::numbers::e_v.val, -10)); - STATIC_ASSERT(test_case(std::numbers::log2e_v.val, -20)); - STATIC_ASSERT(test_case(std::numbers::log10e_v.val, -30)); - STATIC_ASSERT(test_case(std::numbers::pi_v.val, -40)); - STATIC_ASSERT(test_case(std::numbers::inv_pi_v.val, -50)); - STATIC_ASSERT(test_case(std::numbers::inv_sqrtpi_v.val, -60)); - STATIC_ASSERT(test_case(std::numbers::ln2_v.val, -70)); - STATIC_ASSERT(test_case(std::numbers::ln10_v.val, -80)); - STATIC_ASSERT(test_case(std::numbers::sqrt2_v.val, -90)); - STATIC_ASSERT(test_case(std::numbers::sqrt3_v.val, -100)); - STATIC_ASSERT(test_case(std::numbers::inv_sqrt3_v.val, -110)); - STATIC_ASSERT(test_case(std::numbers::egamma_v.val, -120)); - STATIC_ASSERT(test_case(std::numbers::phi_v.val, -130)); - - using F = float; - using D = double; - using L = long double; - - STATIC_ASSERT(test_case(std::numbers::e_v, 0x1.5bf0a8p+1f)); - STATIC_ASSERT(test_case(std::numbers::e_v, 0x1.5bf0a8b145769p+1)); - STATIC_ASSERT(test_case(std::numbers::e_v, 0x1.5bf0a8b145769p+1L)); - STATIC_ASSERT(test_case(std::numbers::e /**/, 0x1.5bf0a8b145769p+1)); - - STATIC_ASSERT(test_case(std::numbers::log2e_v, 0x1.715476p+0f)); - STATIC_ASSERT(test_case(std::numbers::log2e_v, 0x1.71547652b82fep+0)); - STATIC_ASSERT(test_case(std::numbers::log2e_v, 0x1.71547652b82fep+0L)); - STATIC_ASSERT(test_case(std::numbers::log2e /**/, 0x1.71547652b82fep+0)); - - STATIC_ASSERT(test_case(std::numbers::log10e_v, 0x1.bcb7b2p-2f)); - STATIC_ASSERT(test_case(std::numbers::log10e_v, 0x1.bcb7b1526e50ep-2)); - STATIC_ASSERT(test_case(std::numbers::log10e_v, 0x1.bcb7b1526e50ep-2L)); - STATIC_ASSERT(test_case(std::numbers::log10e /**/, 0x1.bcb7b1526e50ep-2)); - - STATIC_ASSERT(test_case(std::numbers::pi_v, 0x1.921fb6p+1f)); - STATIC_ASSERT(test_case(std::numbers::pi_v, 0x1.921fb54442d18p+1)); - STATIC_ASSERT(test_case(std::numbers::pi_v, 0x1.921fb54442d18p+1L)); - STATIC_ASSERT(test_case(std::numbers::pi /**/, 0x1.921fb54442d18p+1)); - - STATIC_ASSERT(test_case(std::numbers::inv_pi_v, 0x1.45f306p-2f)); - STATIC_ASSERT(test_case(std::numbers::inv_pi_v, 0x1.45f306dc9c883p-2)); - STATIC_ASSERT(test_case(std::numbers::inv_pi_v, 0x1.45f306dc9c883p-2L)); - STATIC_ASSERT(test_case(std::numbers::inv_pi /**/, 0x1.45f306dc9c883p-2)); - - STATIC_ASSERT(test_case(std::numbers::inv_sqrtpi_v, 0x1.20dd76p-1f)); - STATIC_ASSERT(test_case(std::numbers::inv_sqrtpi_v, 0x1.20dd750429b6dp-1)); - STATIC_ASSERT(test_case(std::numbers::inv_sqrtpi_v, 0x1.20dd750429b6dp-1L)); - STATIC_ASSERT(test_case(std::numbers::inv_sqrtpi /**/, 0x1.20dd750429b6dp-1)); - - STATIC_ASSERT(test_case(std::numbers::ln2_v, 0x1.62e430p-1f)); - STATIC_ASSERT(test_case(std::numbers::ln2_v, 0x1.62e42fefa39efp-1)); - STATIC_ASSERT(test_case(std::numbers::ln2_v, 0x1.62e42fefa39efp-1L)); - STATIC_ASSERT(test_case(std::numbers::ln2 /**/, 0x1.62e42fefa39efp-1)); - - STATIC_ASSERT(test_case(std::numbers::ln10_v, 0x1.26bb1cp+1f)); - STATIC_ASSERT(test_case(std::numbers::ln10_v, 0x1.26bb1bbb55516p+1)); - STATIC_ASSERT(test_case(std::numbers::ln10_v, 0x1.26bb1bbb55516p+1L)); - STATIC_ASSERT(test_case(std::numbers::ln10 /**/, 0x1.26bb1bbb55516p+1)); - - STATIC_ASSERT(test_case(std::numbers::sqrt2_v, 0x1.6a09e6p+0f)); - STATIC_ASSERT(test_case(std::numbers::sqrt2_v, 0x1.6a09e667f3bcdp+0)); - STATIC_ASSERT(test_case(std::numbers::sqrt2_v, 0x1.6a09e667f3bcdp+0L)); - STATIC_ASSERT(test_case(std::numbers::sqrt2 /**/, 0x1.6a09e667f3bcdp+0)); - - STATIC_ASSERT(test_case(std::numbers::sqrt3_v, 0x1.bb67aep+0f)); - STATIC_ASSERT(test_case(std::numbers::sqrt3_v, 0x1.bb67ae8584caap+0)); - STATIC_ASSERT(test_case(std::numbers::sqrt3_v, 0x1.bb67ae8584caap+0L)); - STATIC_ASSERT(test_case(std::numbers::sqrt3 /**/, 0x1.bb67ae8584caap+0)); - - STATIC_ASSERT(test_case(std::numbers::inv_sqrt3_v, 0x1.279a74p-1f)); - STATIC_ASSERT(test_case(std::numbers::inv_sqrt3_v, 0x1.279a74590331cp-1)); - STATIC_ASSERT(test_case(std::numbers::inv_sqrt3_v, 0x1.279a74590331cp-1L)); - STATIC_ASSERT(test_case(std::numbers::inv_sqrt3 /**/, 0x1.279a74590331cp-1)); - - STATIC_ASSERT(test_case(std::numbers::egamma_v, 0x1.2788d0p-1f)); - STATIC_ASSERT(test_case(std::numbers::egamma_v, 0x1.2788cfc6fb619p-1)); - STATIC_ASSERT(test_case(std::numbers::egamma_v, 0x1.2788cfc6fb619p-1L)); - STATIC_ASSERT(test_case(std::numbers::egamma /**/, 0x1.2788cfc6fb619p-1)); - - STATIC_ASSERT(test_case(std::numbers::phi_v, 0x1.9e377ap+0f)); - STATIC_ASSERT(test_case(std::numbers::phi_v, 0x1.9e3779b97f4a8p+0)); - STATIC_ASSERT(test_case(std::numbers::phi_v, 0x1.9e3779b97f4a8p+0L)); - STATIC_ASSERT(test_case(std::numbers::phi /**/, 0x1.9e3779b97f4a8p+0)); + assert(test_all()); + STATIC_ASSERT(test_all()); }