模组的重载分辨率

Overload resolution of modf

本文关键字:分辨率 重载      更新时间:2023-10-16

我有一个关于modf过载分辨率的问题。

请考虑下面的代码。

#include <iostream>
#include <iomanip>
#include <climits>
#include <cmath>
int main()
{
    unsigned long ul = ULONG_MAX;
    long double ipart;
    long double fpart = std::modf(ul, &ipart);
    std::cout << std::fixed << std::setprecision(0)
        << ul << ", " << ipart << ", " << fpart << 'n'
        << static_cast<double>(ul) << 'n';
}

在我的测试环境中,代码输出...

18446744073709551615, 18446744073709551615, 0
18446744073709551616

参看 http://melpon.org/wandbox/permlink/7ZF2CwqEwBRU5hg4

C++14 标准 26.8[c.math] p.11 说,

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

  1. 如果对应于double参数的任何算术参数具有类型 long double ,则对应于 double参数有效地转换为long double

  2. 否则,如果对应于double参数的任何算术参数具有类型 double 或整数类型,则所有算术 与double参数对应的参数有效地转换为 double .

  3. 否则,与double参数对应的所有算术参数的类型均为 float

变量ul没有类型 long double 而是整数类型,所以我认为ul应该转换为 double,那么ipart应该是18446744073709551616。(也就是说,GCC的行为是错误的。

我对此行为有误解吗?(当然,我认为海湾合作委员会的行为更可取。

你误解了这里发生的事情。

首先,让我们检查ul将被转换为什么,将其作为唯一的参数传递给std::modf

#include <iostream>
#include <iomanip>
#include <climits>
#include <cmath>
int main()
{
    unsigned long ul = ULONG_MAX;
    auto fpart = std::modf(ul, nullptr);
    std::cout << std::fixed << std::setprecision(0)
        << ul << ", " << ipart;
}

这无法编译:

prog.cc:9:46: error: call of overloaded 'modf(long unsigned int&, std::nullptr_t)' is ambiguous
...
/usr/local/gcc-head/include/c++/7.0.0/cmath:376:3: note: candidate: float std::modf(float, float*)
...
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:116:1: note: candidate: double modf(double, double*)
...
/usr/local/gcc-head/include/c++/7.0.0/cmath:380:3: note: candidate: long double std::modf(long double, long double*)
...

如您所见,编译器无法决定调用 3 个重载函数中的哪一个,因为它不知道您想要从传递的参数中调用哪一个。

那你为什么要示例编译呢?

看看你通过的第二个参数表: 指向long double ipart;的指针 .所以这是编译器可以使用的东西。

是否有任何函数将long double *作为第二个参数?是的,有:

long double modf( long double x, long double* iptr );

所以你的代码在这里做的或多或少是这样的:

#include <iostream>
#include <iomanip>
#include <climits>
#include <cmath>
int main()
{
    unsigned long ul = ULONG_MAX;
    long double ipart;
    long double fpart = std::modf(static_cast<long double>(ul), &ipart);
    std::cout << std::fixed << std::setprecision(0)
        << ul << ", " << ipart << ", " << fpart << 'n'
        << static_cast<double>(ul) << 'n';
}

正如您现在所看到的,您正在将static_cast<long double>(ul)static_cast<double>(ul)进行比较。