13

When using the double variant of the std::abs() function without the std with g++ 4.6.1, no warning or error is given.

#include <algorithm>
#include <cmath>

double foobar(double a)
{
     return abs(a);
}

This version of g++ seems to be pulling in the double variant of abs() into the global namespace through one of the includes from algorithm. This looks like it is now allowed by the standard (see this question), but not required.

If I compile the above code using a compiler that does not pull the double variant of abs() into the global namespace (such as g++ 4.2), then the following error is reported:

warning: passing 'double' for argument 1 to 'int abs(int)'

How can I force g++ 4.6.1, and other compilers that pull functions into the global namespace, to give a warning so that I can prevent errors when used with other compilers?

Community
  • 1
  • 1
  • 4
    What's wrong with using `std::abs` if that is the function you need? – Jonathan Leffler Jan 30 '12 at 15:59
  • 3
    @JonathanLeffler Nothing, but it can be easy to miss out by mistake. I don't want that slip to go undetected and cause compilation issues with other compilers. –  Jan 30 '12 at 16:07

2 Answers2

8

The function you are using is actually the integer version of abs, and GCC does an implicit conversion to integer.

This can be verified by a simple test program:

#include <iostream>
#include <cmath>

int main()
{
    double a = -5.4321;
    double b = std::abs(a);
    double c = abs(a);

    std::cout << "a = " << a << ", b = " << b << ", c = " << c << '\n';
}

Output is:

a = -5.4321, b = 5.4321, c = 5

To get a warning about this, use the -Wconversion flag to g++. Actually, the GCC documentation for that option explicitly mentions calling abs when the argument is a double. All warning options can be found here.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • @SamDeHaan Sorry, updated result but forgot to update the code. :) – Some programmer dude Jan 30 '12 at 15:59
  • Is it the standard that has changed or a change in g++'s implementation that causes the implicit conversion with 4.6.1 and not 4.2? Are both valid? –  Jan 30 '12 at 16:09
  • 2
    The above code doesn't compile with my version of g++ (4.4.2). If I add an `#include ` it will, however. And VC++ (VS 2010) calls the double version of `abs`. (I think this is actually the point of the original posting. The behavior is very varied.) Formally, it shouldn't compile in C++03; whether it compiles in C++11 is implementation defined. In practice, however, there's always been a great deal of variation across implementations. – James Kanze Jan 30 '12 at 16:31
1

Be warned, you don't need to explicitly #include <cmath>, <iostream> does the damage as well (and maybe some other headers). Also, note that -Wall doesn't give you any warnings about it.

#include <iostream>

int main() {
  std::cout << abs(.5) << std::endl;
  std::cout << typeid(decltype(abs)).name() << std::endl;
}

Gives output

0
FiiE

On

gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04) 
Nathan Chappell
  • 2,099
  • 18
  • 21