Why code below has no problem with a2 but does not compile for z1?
#include <cmath> // std::nextafter
#include <limits> // std::numeric_limits
int main ()
{
constexpr float a1 {1.f};
constexpr float a2 {std::nextafter(a1, std::numeric_limits<float>::max())};
constexpr float z0 {0.f};
constexpr float z1 {std::nextafter(z0, std::numeric_limits<float>::max())};
return 0;
}
Compiled with GCC 13.2
In file included from <source>:1:
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/cmath: In function 'int main()':
<source>:9:39: in 'constexpr' expansion of 'std::nextafter(((float)z0), std::numeric_limits<float>::max())'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/cmath:2417:32: error: '__builtin_nextafterf(0.0f, 3.40282347e+38f)' is not a constant expression
2417 | { return __builtin_nextafterf(__x, __y); }
So GCC compiled a2 correctly but is unable to compile z1.
Note: Clang 14.0 and MSVC 19.38 have problems even with a2.
libstdc++13.2.0 does not seem to implement
std::nextafter()asconstexpryet.GCC turns
std::nextafter(a1, std::numeric_limits<float>::max())into a constant value. This is a lucky exceptional case when compilers can evaluate rare expressions as constexpr even if they are not marked as such.GCC can't turn
std::nextafter(z0, std::numeric_limits<float>::max())into a constant value, it turns__builtin_nextafterf()into the call to the C functionnextafterf()that can't be constexpr. See https://godbolt.org/z/v7KMrTdfWThe code can be simplified to
with the similar Assembler result: https://godbolt.org/z/KE9vGd6j7