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

时间:2015-07-30 17:19:48

标签: c++ c++11 language-lawyer overload-resolution

请考虑以下事项:

struct A {
    A(float ) { }
    A(int ) { }
};

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

无法编译,但有关A::A的模糊重载的错误。两位候选人都被认为是可行的,因为requirement is simply

  

其次,要使F成为可行的函数,每个参数都应存在一个隐式转换序列(13.3.3.1),它将该参数转换为F的相应参数。

虽然存在从doubleint的隐式转换序列,但A(int )重载不是实际上可行的(在规范的非C ++中) - 标准意义) - 这将涉及缩小转换,因此是不正确的。

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

2 个答案:

答案 0 :(得分:15)

问题在于可以根据类型检测到缩小转换的事实。

在C ++中,有很复杂的方法可以在编译时生成值。

阻止缩小转化率是一件好事。使C ++的重载分辨率比现在更复杂是一件坏事。

在确定重载决策时忽略缩小转换规则(这使得重载决策纯粹与类型有关),然后在选定的重载导致缩小转换时错误输出,使重载决策变得更加复杂,并添加了一种方法检测并防止缩小转换。

只有一个候选者可行的两个例子是在实例化期间“迟到”失败的模板函数,以及复制列表初始化(其中explicit构造函数被考虑,但如果选择它们,则会出现错误)。同样,具有这种影响的重载分辨率会使重载决策变得比现在更加复杂。

现在,有人可能会问,为什么不将纯粹的转换缩小到类型系统?

缩小转换纯粹是基于类型的转换是不可行的。这些更改可能会破坏编译器可以证明有效的大量“遗留”代码。当大多数错误是实际错误时,扫描代码库所需的工作更有价值,而不是新编译器版本是一个混蛋。

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

这会在基于类型的缩小转换下失败,因为0xff的类型为int,而且此类代码非常常见。

如果这些代码需要对int文字进行毫无意义的unsigned char文字修改,那么我们设置一个标志就可以告诉编译器关闭愚蠢的错误。 / p>

答案 1 :(得分:8)

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

  • 首先,不应允许缩小转换。 (不幸的是,这是C兼容性所必需的。在{}初始化禁止缩小内置类型的情况下,这已得到一定程度的纠正。)

鉴于这些,过载规则无需提及这种特殊情况是有道理的。这可能是偶然的便利,但并不是那么有价值。 IMO通常会更好地减少重载决策所涉及的因素,并拒绝更多不明确的事情,迫使程序员明确地解决这些问题。

另外,当double不是常量表达式或double太大时,double to 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};
            ^