7

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()真的没有为 a 定义int,那么为什么上面的程序不会以某种方式失败?

4

6 回答 6

5

10 被隐式转换为双精度数。只要您拥有正确的 sqrt 函数原型,这将自动发生。

编辑:被评论打败

于 2013-10-30T14:06:38.620 回答
5

更新 2

这个问题与一个完全相同的副本合并,看看这个,实际答案比任何人最初想象的要简单得多。当前版本的std_lib_facilities.h包括以下行:

inline double sqrt(int x) { return sqrt(double(x)); }   // to match C++0x

它为int情况创建了一个特定的重载,以匹配现代编译器应该执行的操作,将整数参数转换为 double,尽管此版本并未涵盖所有情况。

如果未使用std_lib_facilities.h,则原始逻辑仍然适用,尽管与原始问题中的Visual Studio 2012gcc-4.2相比相当旧,但有一个版本专门用于整数情况。4.1.2__builtin_sqrt

原来的

2005年左右以来,标准草案要求将整数参数强制转换double,这在草案 C++ 标准中有所介绍。如果我们查看26 Numerics 库部分,然后转到包含标题的 C 部分库26.8 它指定了第8段中涵盖的floatdoublelong double<cmath>的数学函数的重载:

除了 中数学函数的 double 版本外,C++ 还添加了这些函数的 float 和 long double 重载版本,具有相同的语义。

这将ambiguous适用于这种int情况,但标准要求提供足够的重载,以便将整数参数强制转换double。它包含在第11段中,它说(强调我的):

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

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

更新

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

我发现对此进行测试的一种方法gccclang使用long类型,如果我们只有可用的情况下,a该类型与标志一起触发在我的平台上可能改变值的转换的警告。事实上,如果我包含而不是我们可以产生这个警告。虽然我无法在clang中触发这种行为,这似乎表明这是依赖于实现的。-Wconversionsqrt(double)math.hcmath

于 2013-10-30T14:24:04.913 回答
3

因为隐式转换sqrt是为 定义的double,并且int值可以(并且是)隐式转换为类型的值double

(实际上,很难防止使用. C 设计尽可能努力地使代码工作,即使它需要扭曲。其他语言对这类事情要严格得多。)doubleint

于 2013-10-26T23:53:58.867 回答
2

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

请注意,运算符也是简单的函数。因此,您还可以将 an 添加int到 a double,在调用实际添加之前将inta转换为:double

int n = 3;
double x = 1.0;
double sum = n + x;    // implicit conversion of n from int to double
于 2013-10-26T23:54:01.353 回答
1

int因为存在从to的隐式转换double

通过转换,您的代码将如下所示:

cout << "Square root of n == " << sqrt((double)n) << "\n";
于 2013-10-26T23:54:29.840 回答
1

因为编译器实际上是自动(即“隐式”)将整数转换为 a double(或可能long double)并将该值发送到sqrt(). 这是完全正常且完全合法的。

于 2013-10-26T23:55:05.970 回答