Вопрос

Let the source code speak for itself:

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);
}

Compiler generates following error:

E2015 Ambiguity between 'MLine::MLine(int,int,int,int) at shapes.h:100' and 'MLine::MLine(double,double,double,double) at shapes.h:110'

I can resolve this problem by following explicit casting:

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

The partial casting is not sufficient:

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

I am quite confused about rules for implicit casting in expressions. Can someone explain this behaviour? What is the data type of expressions 'x - length_x1' and 'y - length_y1'?

Это было полезно?

Решение

I am quite confused about rules for implicit casting in expressions. Can someone explain this behaviour?

The binary operators (+-*/ etc) work on operands of the same type (and return a result of the same type as their operands). If the types are not the same then one (usually but sometimes both) will be promoted so that both operands have the same type.

What is the data type of expressions 'x - length_x1' and 'y - length_y1'?

X         => int
length_x1 => double

So the types are not the same. So one object will be promoted. In this case X will be promoted to a double (for why look up the promotion rules). The operator - will be applied and the result is a double.

If we now look at your expression:

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

If I now replace the sub expressions with their types:

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

You can now see the dilemma of the compiler. There is no way for it to know which version of the constructor to choose (both can be reached by applying one round of casting). So it must generate an error.

Другие советы

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

The reason why this doesn't work is because the types derived are:

MLine(double, int, double, double)

which is because of ...

Promotion

In operations with mixed operands, the operands might be converted to other types. For operations on floating point types vs. integer types, the integers are converted to floating types first:

float f; int i;
f + i;

f + i is of type float because before the addition takes place, i is converted to float.

This promotion leads to ...

Ambiguity

There is no exact match, and the overload candidates are ambiguous.

Technically (and simplified), the C++ compiler will either use an exact match, or selects the best match out of a set of overload candidates. The rules are non-trivial (one measure being the number of conversions required).

Let me derive some examples:

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

-> Works, because there is only one candidate and double can be implicitly converted to int.

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

-> The second version is used, because it is an exact match.

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

-> Note: This time, we are passing a double. It won't compile, because both overloads require a conversion, are not exact matches, therefore, the candidates are ambiguous.

It is the same with multiple parameters:

#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
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top