在Programming: Principles and Practice using C++(第六次印刷)的第3章中,Stroustrup声明(第68页):“请注意,sqrt()
没有为int
定义”。
这是一个基于该章的简单C ++程序:
#include "std_lib_facilities.h"
int main()
{
int n = 3;
cout << "Square root of n == " << sqrt(n) << "\n";
}
鉴于上面的引用,我希望编译或运行该程序的过程在某种程度上失败。
令我惊讶的是,编译它(使用g ++(GCC)4.2.1)并运行它成功没有错误或警告,并产生以下非常好的输出:
Square root of n == 1.73205
因此我的问题是:如果sqrt()
确实没有为int
定义,那么为什么上面的程序不能以某种方式失败?
更新2
这个问题与一个完全重复的问题合并在一起,看看这个,实际答案比任何人原先想象的要简单得多。 std_lib_facilities.h的当前版本包括以下行:
inline double sqrt(int x) { return sqrt(double(x)); } // to match C++0x
这为int情况创建了一个特定的重载,以匹配现代编译器应该做的事情,即将整数参数转换为double,尽管此版本并未涵盖所有情况。
如果没有使用std_lib_facilities.h而不是原始逻辑仍然适用,虽然gcc-4.2
与原始问题的Visual Studio 2012相比相当陈旧,但是4.1.2
版本使用__builtin_sqrt
专门用于整数情况。
原版的
自2005年左右起,标准草案要求将整数参数转换为加倍,这将在draft C++ standard中涵盖。如果我们查看26
Numerics库中的部分,然后转到涵盖26.8
头的<cmath>
C库部分,它指定了第8段中介绍的float,double和long double的数学函数的重载:
除了数学函数的双重版本之外,C ++还添加了这些函数的float和long double重载版本,具有相同的语义。
对于ambiguous
案例,这将是int
,但标准要求提供足够的重载,以便将整数参数转换为double。第11段涉及(强调我的):
此外,还应有足够的额外过载来确保:
- 如果对应于double参数的任何算术参数具有long double类型,则对应于double参数的所有算术参数都被有效地转换为long double。
- 否则,如果对应于double参数的任何算术参数具有double类型或整数类型,则对应于double参数的所有算术参数将被有效地转换为double。
- 否则,对应于double参数的所有算术参数都具有float类型。
更新
正如@nos所指出的那样,被调用的sqrt
的版本可能来自math.h
头而不是来自cmath
的重载,如果是这种情况并且可能存在实现定义的警告那么我们可能会恢复到旧的C样式行为,如果唯一可用的版本是sqrt(double)
,这意味着int将被隐式转换为double。
我发现在gcc
和clang
上测试这个的一种方法是使用long类型的a
,如果我们只有-Wconversion
,那么sqrt(double)
标志会触发警告我的平台上可能有价值的改变转换。事实上,如果我包括math.h
而不是cmath
,我们可以产生这个警告。虽然我不能在clang中触发这种行为,这似乎表明这是依赖于实现的。
10被隐式转换为双。只要您拥有sqrt的正确函数原型,就会自动执行此操作。
编辑:被评论殴打
因为隐式转换。 sqrt
是为double
定义的,int
值可以(并且)隐式转换为double
类型的值。
(实际上很难阻止使用double
调用int
的函数。你可能会让你的编译器发出警告,但由于这通常是一个保值转换,即使这可能很难.C ++从C继承设计尽可能努力使代码工作,即使它需要扭曲。其他语言对这类事情要严格得多。)
sqrt
是为double
定义的。 C ++允许您隐式地将int
转换为double
。
int n = 3;
double x = sqrt(n); // implicit conversion of n from int to double
将值用作函数参数或将其指定给变量时,可能会发生隐式转换。
第二种情况的一个例子是:
int n = 3;
double x = n; // implicit conversion of n from int to double
请注意,运算符也只是函数。因此,您还可以将int
添加到double
,它会在调用实际添加之前将int
转换为double
:
int n = 3;
double x = 1.0;
double sum = n + x; // implicit conversion of n from int to double
因为有从int
到double
的隐含转换。
通过转换,您的代码将如下所示:
cout << "Square root of n == " << sqrt((double)n) << "\n";
因为编译器实际上是自动地(即“隐式地”)将整数转换为double
(或者可能是long double
)并将该值发送到sqrt()
。这完全是正常的,完全合法的。