为什么缩小不会影响过载分辨率?

Why doesn't narrowing affect overload resolution?

本文关键字:分辨率 影响 缩小 为什么      更新时间:2023-10-16

考虑以下内容:

struct A {
    A(float ) { }
    A(int ) { }
};
int main() {
    A{1.1}; // error: ambiguous
}

编译失败,并出现关于A::A的模糊过载的错误。这两个候选都被认为是可行的,因为需求很简单:

第二,要使F是可行函数,每个实参必须存在一个隐式转换序列(13.3.3.1),将该实参转换为F的相应形参。

虽然存在从doubleint的隐式转换序列,但A(int )过载实际上不是可行的(在规范的,非c++标准意义上)-这将涉及窄化转换,因此是病态的。

为什么在确定可行候选人的过程中不考虑缩小转换?有没有其他情况下,尽管只有一个候选是可行的,重载还是被认为是模棱两可的?

问题在于可以不基于类型检测窄化转换。

在c++中有非常复杂的方法在编译时生成值。

阻塞窄化转换是一件好事。使c++的重载解析比现在更复杂是一件坏事。

在确定重载解析时忽略窄化转换规则(这使得重载解析纯粹是关于类型的),然后在选择的重载导致窄化转换时出错,使重载解析变得更加复杂,并增加了一种检测和防止窄化转换的方法。

只有一个候选可行的例子是模板函数"后期"失败,在实例化和复制列表初始化期间(其中考虑explicit构造函数,但如果选择它们,则会得到一个错误)。类似地,使用影响重载解析会使重载解析比现在更加复杂。

现在,有人可能会问,为什么不将窄化转换完全折叠到类型系统中呢?

使窄化转换完全基于类型是不可行的。这样的更改可能会破坏大量的"遗留"代码,编译器可以证明是有效的。当大多数错误都是实际错误,而不是新编译器版本是一个混蛋时,清理代码库所需的努力是值得的。

unsigned char buff[]={0xff, 0x00, 0x1f};

在基于类型的窄化转换下会失败,因为0xffint类型,这样的代码很常见。

如果这样的代码需要将int字面量无意义地修改为unsigned char字面量,那么很可能会以我们设置一个标志来告诉编译器停止这个愚蠢的错误而结束。

  • 缩窄是编译器只知道内置类型的东西。用户定义的隐式转换不能标记为窄化或不窄化

  • 一开始就不允许使用隐式窄化转换。(不幸的是,它是C兼容性所必需的。{}初始化禁止对内置类型进行窄化,这在一定程度上得到了纠正。

考虑到这些,重载规则不费心提及这种特殊情况是有意义的。这可能是一个偶然的方便,但它并不是那么有价值。在我看来,通常情况下,在重载解析中涉及的因素越少越好,并将更多的东西视为不明确的,从而迫使程序员显式地解决这些问题。

另外,当双精度数不是常量表达式或双精度数太大时,double到float是一种窄化转换。

#include <iostream>
#include <iomanip>
int main() {
    double d{1.1};
    float f{d};
    std::cout << std::setprecision(100) << d << " " << f << 'n';
}

这通常会产生错误:

main.cpp:7:13: error: non-constant-expression cannot be narrowed from type 'double' to 'float' in initializer list [-Wc++11-narrowing]
    float f{d};
            ^