如果没有为int定义,为什么sqrt()在int变量上工作正常?

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,为什么上面的程序不能以某种方式失败?

tan*_*grs 5

10被隐式转换为双.只要您拥有sqrt的正确函数原型,就会自动执行此操作.

编辑:被评论殴打


Sha*_*our 5

更新 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段中,其中说(强调我的):

此外,还应有足够的额外过载以确保:

  1. 如果与 double 参数对应的任何算术参数具有 long double 类型,则与 double 参数对应的所有算术参数都被有效地强制转换为 long double。
  2. 否则,如果与 double 参数对应的任何算术参数具有 double 类型或整数类型,则与 double 参数对应的所有算术参数都被有效地强制转换为 double。
  3. 否则,与双精度参数对应的所有算术参数都具有 float 类型。

更新

正如@nos 指出的那样,sqrt被调用的版本可能来自math.h标头,而不是来自 的重载cmath,如果是这种情况并且可能在此处定义了一个实现,那么我们可能会恢复到旧的C 风格行为,如果唯一可用的版本是sqrt(double)这意味着int将被隐式转换为double。

一种方法,我发现这个测试对gcc和clang是使用长类型a与沿-Wconversion标志触发警告我的平台上的潜在价值转化改变,如果我们只有sqrt(double)用。事实上,如果我包括math.h而不是cmath我们可以产生这个警告。虽然我无法在clang 中触发这种行为,这似乎表明这是依赖于实现的。