Promotion of parameters during overloading

1.2k views Asked by At

I was studying about overloading and I am completely getting confused with promotions. I looked at few articles in SO (implicit conversion sequence in function overloading) and I am sure some more are available, but could not find the right article. I was also referring to http://www.dcs.bbk.ac.uk/~roger/cpp/week20.htm. I was looking at C++ Programming special edition by Stroustrup and came across following explanation.

Finding the right version to call from a set of overloaded functions is done by looking for a best match between the type of the argument expression and the parameters (formal arguments) of the functions. To approximate our notions of what is reasonable, a series of criteria are tried in order: 1 Exact match [2] Match using promotions; [3] Match using standard conversions [4] Match using user-defined conversions [5] Match using the ellipsis ......

void print(int);
void print(double);
void print(long);
void print(char);
void h(char c, int i, short s, float f)
{
    print(s); // integral promotion: invoke print(int)
    print(f); // float to double promotion: print(double)
}

I wrote below code. I was thinking that if I call the function with value of 1, func1(long) will be called because promotion takes place. But I get error message "error: call of overloaded 'func1(int)' is ambiguous". It is not calling the function with even unsigned char type of variable.

Also if I pass call func1(3.4f), func1(double) is called and promotion takes place as per my expectation. Why 1 is not promoted to long int but why float is promoted to double? What integer promotions takeplace?

    void func1(unsigned char speed)
    {
        cout<<"Func1 with unsigned char: speed =" << speed <<" RPM\n";
    }

   void func1(long speed)
    {
        cout<<"Func1 with long Int: speed =" << speed <<" RPM\n";
    }

    void func1(double speed)
    {
        cout<<"Func1 with double: speed =" << speed <<" RPM\n";
    }

    int main(void)
    {
        func1(1);
        func1(3.4f);
        return(0);
    }
2

There are 2 answers

4
gsamaras On BEST ANSWER

The standard specifies:

[C++11: 4.13/1]: ("Integer conversion rank")

Every integer type has an integer conversion rank defined as follows:

  • [..]
  • The rank of long long int shall be greater than the rank of long int, which shall be greater than the rank of int, which shall be greater than the rank of short int, which shall be greater than the rank of signed char.
  • The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type.
  • [..]

which calls for ambiguity in your example.

As for func1(3.4f);, it's just a promotion from float to double, and that's the best match, since the other two overloaded methods have long and unsigned char.

Also check this table:

enter image description here

where a subclause specifies:

[conv.fpprom]: (7.7 Floating-point promotion )

  • A prvalue of type float can be converted to a prvalue of type double. The value is unchanged.
  • This conversion is called floating-point promotion.
0
ev lev On

Short answer: In most cases only conversions from types smaller then int to int, and float to double are considered "promotions", and thus are a better match then all other implicit conversions.

So counter intuitive - int to long or int to double or int to char - are all considered as matches of the same level and thus are ambiguous.

IMPORTANT: "promotion" in this context has a different meaning from "promotion rules" in discussing a mixed type arithmetic expression: (short)6+(float)78

Long answer: enums, modern char types (w_char, char8_t...) and bit fields have some exceptions to this rule, see the standard or https://en.cppreference.com/w/cpp/language/implicit_conversion the section about "Integral promotion"