sam*_*per 7 c++ gcc g++ gcc4 gcc-4.2
在编程:使用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";
}
Run Code Online (Sandbox Code Playgroud)
鉴于上面的引用,我希望编译或运行该程序的过程在某种程度上失败.
令我惊讶的是,编译它(使用g ++(GCC)4.2.1)并运行它成功没有错误或警告,并产生以下非常好的输出:
Square root of n == 1.73205
Run Code Online (Sandbox Code Playgroud)
因此我的问题是:如果sqrt()真的没有为a定义int,为什么上面的程序不能以某种方式失败?
更新 2
这个问题与一个完全重复的问题合并,看看这个,实际答案比任何人最初想象的要简单得多。std_lib_facilities.h的当前版本包括以下行:
inline double sqrt(int x) { return sqrt(double(x)); } // to match C++0x
Run Code Online (Sandbox Code Playgroud)
它为int案例创建了一个特定的重载,以匹配现代编译器应该做的事情,将整数参数强制转换为 double,尽管此版本并未涵盖所有情况。
如果std_lib_facilities.h没有被使用,那么原始逻辑仍然适用,虽然gcc-4.2与原始问题中的Visual Studio 2012相比相当旧,但一个4.1.2版本__builtin_sqrt专门用于整数情况。
原来的
自2005年左右以来,标准草案要求将整数参数强制转换为两倍,这在C++ 标准草案中有所涵盖。如果我们查看数字26 库部分,然后转到涵盖标题的26.8 C部分库<cmath>,它指定了第8段中涵盖的float、double和long double数学函数的重载:
除了 中数学函数的 double 版本,C++ 还添加了这些函数的 float 和 long double 重载版本,语义相同。
这将ambiguous适用于这种int情况,但标准要求提供足够的重载,以便将整数参数强制转换为double。它包含在第11段中,其中说(强调我的):
此外,还应有足够的额外过载以确保:
- 如果与 double 参数对应的任何算术参数具有 long double 类型,则与 double 参数对应的所有算术参数都被有效地强制转换为 long double。
- 否则,如果与 double 参数对应的任何算术参数具有 double 类型或整数类型,则与 double 参数对应的所有算术参数都被有效地强制转换为 double。
- 否则,与双精度参数对应的所有算术参数都具有 float 类型。
更新
正如@nos 指出的那样,sqrt被调用的版本可能来自math.h标头,而不是来自 的重载cmath,如果是这种情况并且可能在此处定义了一个实现,那么我们可能会恢复到旧的C 风格行为,如果唯一可用的版本是sqrt(double)这意味着int将被隐式转换为double。
一种方法,我发现这个测试对gcc和clang是使用长类型a与沿-Wconversion标志触发警告我的平台上的潜在价值转化改变,如果我们只有sqrt(double)用。事实上,如果我包括math.h而不是cmath我们可以产生这个警告。虽然我无法在clang 中触发这种行为,这似乎表明这是依赖于实现的。