gcem
gcem copied to clipboard
_copysign cannot be used in constant context (MSVC 16 2019)
Building GCEM in a project using Cmake on Windows 10, and with MSVC 16 2019 as the compiler fails, it appears that the implementation of _copysign cannot be used in a constant context. Many errors were thrown of the form:
C:\Users\61405\source\repos\BGNC\extern\gcem\include\gcem_incl/neg_zero.hpp(34,31): message : see usage of '_copysign' [C:\Users\61405\source\repos\BGNC\build\tests\BGNCTestExec.vcxproj]
C:\Users\61405\source\repos\BGNC\tests\coordinates_tests\earth_tests.cpp(129,28): error C2131: expression did not evaluate to a constant [C:\Users\61405\source\repos\BGNC\build\tests\BGNCTestExec.vcxproj]
C:\Users\61405\source\repos\BGNC\extern\gcem\include\gcem_incl/neg_zero.hpp(34,31): message : failure was caused by call of undefined function or one not declared 'constexpr' [C:\Users\61405\source\repos\BGNC\build\tests\BGNCTestExec.vcxproj]
The same code compiled fine when using GCC.
I've confirmed that the errors are removed by manually implementing a version of copysign:
#gcem_options.hpp
template <typename T>
constexpr T HACK_MSVCcopysign(T x, T y)
{
if ((x < 0 && y > 0) || (x > 0 && y < 0))
{
return -x;
}
return x;
}
#ifdef _MSC_VER
#ifndef GCEM_SIGNBIT
#define GCEM_SIGNBIT(x) _signbit(x)
#endif
#ifndef GCEM_COPYSIGN
// #define GCEM_COPYSIGN(x,y) _copysign(x,y)
#define GCEM_COPYSIGN(x,y) HACK_MSVCcopysign(x, y)
#endif
...
Unfortunately, your approach does not cover signed zeros - try HACK_MSVCcopysign(1.0, -0.0).
If MSVC's _fpclass(x) function is constexpr friendly, then the new gcem::copysign function will provide a workaround.
template <typename T>
constexpr bool signbit(const T x) noexcept
{
#if defined(__clang__) || defined(__GNUC__)
return __builtin_signbit(x);
#else
static_assert(sizeof(T) == 4 || sizeof(T) == 8);
using uint = std::conditional_t<sizeof(T) == 4, std::uint32_t, std::uint64_t>;
return std::bit_cast<uint>(x) & (uint{ 1 } << (sizeof(T) * 8 - 1));
#endif
}