I can't give a good reason for why abs couldn't be constexpr and apparently neither can gcc. When I use gcc 4.9.2 with this program:
#include <cstdlib>
#include <cinttypes>
#include <cassert>
constexpr intmax_t abs3 = std::abs(3);
constexpr intmax_t absneg3 = std::abs(-3);
int main()
{
assert(abs3 == absneg3);
}
it compiles and runs to completion with no warnings or errors. You can try it here. However, clang++ (version 3.5.0) throws a compile-time error:
abs.cpp:6:20: error: constexpr variable 'abs3' must be initialized by a constant expression.
I think that clang++ actually gets it right here, because in section 27.9.2 [c.files] of the 2011 standard, it says:
The contents of header are the same as the Standard C Library header , with the following changes:
— the header includes the header instead of , and
— if and only if the type intmax_t designates an extended integer type (3.9.1), the following function signatures are added:
intmax_t abs(intmax_t);
imaxdiv_t div(intmax_t, intmax_t);
which shall have the same semantics as the function signatures intmax_t imaxabs(intmax_t) and imaxdiv_t imaxdiv(intmax_t, intmax_t), respectively.
In the current working draft of the C++ standard, as in the published 2014 version, it says in section 17.6.5.6 [constexpr.functions]:
This standard explicitly requires that certain standard library functions are constexpr (7.1.5). An implementation shall not declare any standard library function signature as constexpr except for those where it is explicitly required.
So the result, for now, is that these functions are still not constexpr according to the standard (which you knew) but they could be, as demonstrated by the gcc compiler.
I can't give a good reason for why abs couldn't be constexpr and apparently neither can gcc. When I use gcc 4.9.2 with this program:
#include <cstdlib>
#include <cinttypes>
#include <cassert>
constexpr intmax_t abs3 = std::abs(3);
constexpr intmax_t absneg3 = std::abs(-3);
int main()
{
assert(abs3 == absneg3);
}
it compiles and runs to completion with no warnings or errors. You can try it here. However, clang++ (version 3.5.0) throws a compile-time error:
abs.cpp:6:20: error: constexpr variable 'abs3' must be initialized by a constant expression.
I think that clang++ actually gets it right here, because in section 27.9.2 [c.files] of the 2011 standard, it says:
The contents of header are the same as the Standard C Library header , with the following changes:
— the header includes the header instead of , and
— if and only if the type intmax_t designates an extended integer type (3.9.1), the following function signatures are added:
intmax_t abs(intmax_t);
imaxdiv_t div(intmax_t, intmax_t);
which shall have the same semantics as the function signatures intmax_t imaxabs(intmax_t) and imaxdiv_t imaxdiv(intmax_t, intmax_t), respectively.
In the current working draft of the C++ standard, as in the published 2014 version, it says in section 17.6.5.6 [constexpr.functions]:
This standard explicitly requires that certain standard library functions are constexpr (7.1.5). An implementation shall not declare any standard library function signature as constexpr except for those where it is explicitly required.
So the result, for now, is that these functions are still not constexpr according to the standard (which you knew) but they could be, as demonstrated by the gcc compiler.
It has been proposed in P0533:
A function in
<cmath>shall be declaredconstexprif and only if:
- When taken to act on the set of rational numbers, the function is closed (excluding division by zero);
- The function does not modify any of its arguments which have external visibility;
- The function is not strongly dependent on the rounding mode.
By means of a brief illustration,
abssatisfies all three criteria; however, functions such asexp,sqrt,cos,sinfall foul of the first criterion and so are excluded asconstexprcandidates. Finally, as discussed above,nearbyintfails the final criterion.
Hi everyone,
I hope you are doing fine in those trouble time.
I came here because, in a program I working on, I wanted to see how much I could `constexpr` all the things, and I ended with `std::abs` restricted me.
Indeed, the function `std::abs` is not `constexpr`, but it seems that it could be, I experimented a bit on godbolt.
Is there a reason why `std::abs` is not `constexpr` in C++17, and maybe not in C++20 either ?
Thank you in advance for you answers :)
Link to std::abs documentation
[solved] Why does my Abs function crash but not std::abs? - General JUCE discussion - JUCE
c++ - Generic absolute value function - Code Review Stack Exchange
c++ - std::abs can be used in constexpr function, but only if it's templated. Why? - Stack Overflow
std::abs and constexpr
I believe you have a bug in your generic implementation, especially in relation to floating-point style classes that have signed-zero values:
your code:
return (T{} < value) ? value : -value;
would be better as a T{} <= value (or rewritten as (T{} > value) ? -value : value;).
Your current logic will return -0.0 for an input value of 0.0, and that's not appropriate for an abs() function.
Additionally, I don't know how you would really test these things, because, if I am not mistaken, in floating-point comparisons with signed-zero values, -0.0 == 0.0 yet I would expect that abs(-0.0) would return 0.0.
How you resolve this issue though, I don't know.
The only point I'd make it to look into using boost::call_traits ( see here ). Instead of always passing by const T&, this will select the "best" way to pass a parameter: by const T for small, built in types (such as int), and by const T& for class types.
template<typename T>
constexpr auto abs(boost::call_traits<T>::param_type value)
-> T
{ ... }