Search code examples
c++implicit-conversionc++builder-xeambiguous-call

Ambiguity between 'function1' and 'function2' (C++)


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'?


Solution

  • 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.