Ambiguous overload call to abs(double)

I have the following C++ code:

#include <math.h>
#include <cmath.h>      // per http://www.cplusplus.com/reference/clibrary/cmath/abs/

// snip ...

if ( (loan_balance < 0) && (abs(loan_balance) > loan_payment) ) {
    ...
}

and make blows up on:

error: call of overloaded 'abs(double)' is ambiguous

also of interest:

/usr/include/stdlib.h:785: note: candidates are: int abs(int)

How can I specify that the compiler needs to call the abs() in cmath.h that can handle floats?

Compiler info (Not sure if this matters):

[some_man@some_box ~/some_code]#  gcc -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr    /share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=i386-redhat-linux
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)

Solution 1:

The header <math.h> is a C std lib header. It defines a lot of stuff in the global namespace. The header <cmath> is the C++ version of that header. It defines essentially the same stuff in namespace std. (There are some differences, like that the C++ version comes with overloads of some functions, but that doesn't matter.) The header <cmath.h> doesn't exist.

Since vendors don't want to maintain two versions of what is essentially the same header, they came up with different possibilities to have only one of them behind the scenes. Often, that's the C header (since a C++ compiler is able to parse that, while the opposite won't work), and the C++ header just includes that and pulls everything into namespace std. Or there's some macro magic for parsing the same header with or without namespace std wrapped around it or not. To this add that in some environments it's awkward if headers don't have a file extension (like editors failing to highlight the code etc.). So some vendors would have <cmath> be a one-liner including some other header with a .h extension. Or some would map all includes matching <cblah> to <blah.h> (which, through macro magic, becomes the C++ header when __cplusplus is defined, and otherwise becomes the C header) or <cblah.h> or whatever.

That's the reason why on some platforms including things like <cmath.h>, which ought not to exist, will initially succeed, although it might make the compiler fail spectacularly later on.

I have no idea which std lib implementation you use. I suppose it's the one that comes with GCC, but this I don't know, so I cannot explain exactly what happened in your case. But it's certainly a mix of one of the above vendor-specific hacks and you including a header you ought not to have included yourself. Maybe it's the one where <cmath> maps to <cmath.h> with a specific (set of) macro(s) which you hadn't defined, so that you ended up with both definitions.

Note, however, that this code still ought not to compile:

#include <cmath>

double f(double d)
{
  return abs(d);
}

There shouldn't be an abs() in the global namespace (it's std::abs()). However, as per the above described implementation tricks, there might well be. Porting such code later (or just trying to compile it with your vendor's next version which doesn't allow this) can be very tedious, so you should keep an eye on this.

Solution 2:

Its boils down to this: math.h is from C and was created over 10 years ago. In math.h, due to its primitive nature, the abs() function is "essentially" just for integer types and if you wanted to get the absolute value of a double, you had to use fabs(). When C++ was created it took math.h and made it cmath. cmath is essentially math.h but improved for C++. It improved things like having to distinguish between fabs() and abs, and just made abs() for both doubles and integer types. In summary either: Use math.h and use abs() for integers, fabs() for doubles or use cmath and just have abs for everything (easier and recommended)

Hope this helps anyone who is having the same problem!