In chapter 3 of Programming: Principles and Practice using C++ (sixth printing), Stroustrup states (p.68): "Note that sqrt()
is not defined for an int
".
Here is a simple C++ program based on that chapter:
#include "std_lib_facilities.h"
int main()
{
int n = 3;
cout << "Square root of n == " << sqrt(n) << "\n";
}
Given the quote above, I would expect the process of compiling or running this program to fail in some way.
To my surprise, compiling it (with g++ (GCC) 4.2.1) and running it succeeded without errors or warnings, and produced the following perfectly decent output:
Square root of n == 1.73205
My question therefore is: if sqrt()
really is not defined for an int
, then why doesn't the program above fail somehow?
The 10 is being implicitly converted to a double. This will happen automatically as long as you have the correct function prototype for sqrt.
Edit: beaten by comments
Because of implicit conversions.
sqrt
is defined fordouble
, and anint
value can be (and is) converted implicitly to a value of typedouble
.(It is in fact pretty hard to prevent a function that takes a
double
from being called with anint
. You may get your compiler to emit a warning, but since this is typically a value-preserving conversion, even that may be hard. C++ inherits from C the design to try as hard as possible to make code work, even if it requires contortions. Other languages are much stricter about this sort of thing.)Because there's an implicit conversion from
int
todouble
.With the conversion, your code would look like this:
Because the compiler is actually automatically (i.e. "implicitly") converting the integer to a
double
(or maybelong double
) and sending that value tosqrt()
. This is completely normally and completely legal.Update 2
This question was merged with an exact duplicate, on taking a look at this, the actual answer is much simpler than anyone originally thought. The current version of std_lib_facilities.h includes the following line:
which creates a specific overload for the int case to match what modern compilers should be be doing which is cast integer arguments to double, although this version does not cover all the cases.
If std_lib_facilities.h was not being used than the original logic still applies, although
gcc-4.2
is rather old compared to Visual Studio 2012 from the original question but a4.1.2
version have uses__builtin_sqrt
specifically for the integer case.Original
Since around 2005 the draft standard required integer argument to be cast to double this is covered in the draft C++ standard. If we look in section
26
Numerics library and then go to section26.8
C library which covers the<cmath>
header, it specifies overloads of the math functions for float, double and long double which is covered in paragraph 8:which would be
ambiguous
for theint
case but the standard requires that sufficient overload are provided so that integer arguments are cast to double. It is covered in paragraph 11 which says(emphasis mine):Update
As @nos points out it is possible that the version of
sqrt
being called is frommath.h
header as opposed to the overloads fromcmath
, if that is the case and there is likely a implementation defined caveat here then we may be reverting to old C style behavior if the only version available issqrt(double)
which would mean that int would be converted to double implicitly.One way I found to test this on
gcc
andclang
would be to use long type fora
which along with-Wconversion
flag triggers a warning for a potentially value altering conversion on my platform if we only havesqrt(double)
available. Indeed if I includemath.h
instead ofcmath
we can produce this warning. Although I can not trigger this behavior in clang which seems to indicate this is implementation dependent.sqrt
is defined fordouble
. And C++ allows you to convertint
todouble
implicitly.Implicit conversions may happen when you use the value as a function parameter or assign it to a variable.
An example for the second case would be:
Note that operators are also simply functions. Thus, you can also add an
int
to adouble
, which converts theint
to adouble
before invoking the actual addition: