I've come across a few different examples of ways in which std::abs
can give unexpected results:
- This question (On the std::abs function) points out that
<cstdlib>
provides overloads for integral types while<cmath>
provides overloads for floating point types. Failing to include the correct header gives undefined behaviour, which the compiler is allowed to silently accept - C++ Defect report 2735 points out that the C++11 and C++14 standards technically require that
std::abs(short)
returns adouble
, although most compilers ignore the relevant wording and return anint
. The resolution to this issue indicates that the wording was changed in C++17 so thatstd::abs(short)
returns anint
- The answers to this question (When do I use fabs and when is it sufficient to use std::abs?) point out that relying on
std::abs
can lead to difficult-to-spot bugs, since (in modern C++) the headers which introducestd::abs
are allowed to introduce a globalabs
function (which may or may not have the same overloads), and it's easy to accidentally useabs
instead ofstd::abs
The fixes that I am aware of are:
- Avoid undefined behaviour: include
<cstdlib>
if evaluatingstd::abs([integral type])
and<cmath>
if evaluatingstd::abs([floating point type])
- Two options:
- Use C++17 or pre-(C++11)
- Work around the fact that
std::abs(short)
may return anint
or adouble
depending on the compiler's compliance with the C++11/C++14 standard
- Two options:
- Pass gcc the flag
–Wconversion
so that calls likeabs(2.0)
trigger a warning at compilation - Use a trick (adapted from n.m.'s answer to (Disable math.h crap when working with cmath)) to make to the global
abs
ambiguous
- Pass gcc the flag
Trick:
namespace neveruse{
int abs(int);
}
using namespace neveruse;
Question: Is there a reason to prefer one of the solutions to issue 3 over the other? Do any of these fixes introduce other potential problems that I need to watch out for?