【问题标题】:Ambiguity between 'function1' and 'function2' (C++)“function1”和“function2”之间的歧义(C++)
【发布时间】:2012-04-17 08:55:44
【问题描述】:

让源代码自己说话:

MLine::MLine(int x1, int y1, int x2, int y2)
{
}

MLine::MLine(double x1, double y1, double x2, double y2)
{
}

void __fastcall TVctDiag2::PrepareArrowTail(int x, int y)
{
    double length_x1;
    double length_y1;
    MLine *line = new MLine(x, y, x - length_x1, y - length_y1);
}

编译器产生以下错误:

E2015 'MLine::MLine(int,int,int,int) at shapes.h:100' 和 'MLine::MLine(double,double,double,double) at shapes.h:110' 之间的歧义

我可以通过以下显式转换来解决这个问题:

    MLine *line = new MLine((double)x, (double)y, x - length_x1, y - length_y1);

部分转换是不够的:

    MLine *line = new MLine((double)x, y, x - length_x1, y - length_y1);

我对表达式中隐式转换的规则感到很困惑。有人可以解释这种行为吗?表达式'x - length_x1'和'y - length_y1'的数据类型是什么?

【问题讨论】:

  • x - length_x1 和 y - length_y1 的类型是 double,x,y 的类型是 int。所以编译器不知道使用哪个函数。它试图在 MLine(int, int, int, int) 和 MLine(double, double, double, double) 之间比较 MLine(int, int, double, double)。 MLine(double, int, double, double) 也有同样的问题。
  • 我认为由于二元减号运算符的关联性是从左到右的,所以在减法之前将length_x1转换为int。
  • 表达式产生的类型几乎从不依赖于元素的顺序。 int 与 double 混合总是产生一个 double。
  • @truthseeker:在这里查看promotion rules
  • 在编写绘图框架时,通常整数或浮点数都有意义,但不能同时使用。我会删除其中一个重载,一切都会好起来的。

标签: c++ implicit-conversion c++builder-xe ambiguous-call


【解决方案1】:

我对表达式中隐式转换的规则感到很困惑。有人可以解释这种行为吗?

二元运算符(+-*/ 等)作用于相同类型的操作数(并返回与其操作数相同类型的结果)。如果类型不同,则将提升一个(通常但有时两者兼有)以使两个操作数具有相同的类型。

表达式'x - length_x1'和'y - length_y1'的数据类型是什么?

X         => int
length_x1 => double

所以类型不一样。因此将提升一个对象。在这种情况下,X 将被提升为双精度(为什么要查找 promotion rules)。运算符 - 将被应用,结果是双精度。

如果我们现在看看你的表情:

MLine *line = new MLine(x, y, x - length_x1, y - length_y1);

如果我现在用它们的类型替换子表达式:

MLine *line = new MLine(<int>, <int>, <double>, <double>);

您现在可以看到编译器的困境。它无法知道选择哪个版本的构造函数(都可以通过应用一轮强制转换来实现)。所以它一定会产生错误。

【讨论】:

    【解决方案2】:
    MLine *line = new MLine((double)x, y, x - length_x1, y - length_y1);
    

    这不起作用的原因是派生的类型是:

    MLine(double, int, double, double)
    

    这是因为……

    促销

    在混合操作数的操作中,操作数可能会转换为其他类型。对于浮点类型与整数类型的操作,首先将整数转换为浮点类型:

    float f; int i;
    f + i;
    

    f + i 的类型为 float,因为在添加之前,i 被转换为 float

    此促销活动导致...

    歧义

    没有完全匹配,重载候选项不明确。

    从技术上讲(和简化),C++ 编译器将使用精确匹配,或者从一组重载候选中选择最佳匹配。规则很重要(一个衡量标准是所需的转换次数)。

    让我举几个例子:

    void foo (int) {}
    int main () { foo(5.f); }
    

    -> 有效,因为只有一个候选者,并且 double 可以隐式转换为 int。

    #include <iostream>
    void foo (int) { std::cout << "foo(int)\n"; }
    void foo (float) { std::cout << "foo(float)\n"; }
    int main () { foo(5.f); }
    

    -> 使用第二个版本,因为它是完全匹配的。

    #include <iostream>
    void foo (int) { std::cout << "foo(int)\n"; }
    void foo (float) { std::cout << "foo(float)\n"; }
    int main () { foo(5.); }
    

    -> 注意:这一次,我们传递了一个double。它不会编译,因为两个重载都需要转换,不是完全匹配,因此候选者是不明确的。

    多参数同理:

    #include <iostream>
    void foo (int,int) { std::cout << "foo(int,int)\n"; }
    void foo (float,float) { std::cout << "foo(float,float)\n"; }
    int main () { 
        foo(5.f, 5.f); // exact match with the (float,float) overload
        foo (5, 5);    // exact match with the (int,int) overload
        foo (5, 5.f);  // No exact match, and candidates are ambiguous
    }
    

    【讨论】:

      猜你喜欢
      • 2018-04-03
      • 1970-01-01
      • 2018-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 2016-04-21
      • 2011-01-15
      相关资源
      最近更新 更多