Home > Mobile >  How to determine two implicit conversion sequences preferred than each other for overload resolution
How to determine two implicit conversion sequences preferred than each other for overload resolution

Time:11-14

I want to question about overload resolution accompanying an implicit type conversion. This question refers cppreference 1 and 2.

It seems that an implicit conversion sequence has at most three steps to convert an type T1(argument type) to T2(parameter type):

  1. zero or one standard conversion sequence;
  2. zero or one user-defined conversion; ( I want to ignore this step because it isn't related to this question.)
  3. zero or one standard conversion sequence.

An implicit conversion sequence can be categorized as one of:

  • a standard conversion sequence (I am interested this fundamental type conversions case only.)
  • a user-defined conversion sequence
  • an ellipsis conversion sequence

And, each type of standard conversion sequence is assigned one of three ranks:

  1. Exact match : no conversion required, lvalue-to-rvalue conversion, qualification conversion, function pointer conversion, user-defined conversion of class type to the same class
  2. Promotion : integral promotion, floating-point promotion
  3. Conversion : integral conversion, floating-point conversion, floating-integral conversion, pointer conversion, pointer-to-member conversion, boolean conversion, user-defined conversion of a derived class to its base

And,

The rank of the standard conversion sequence is the worst of the ranks of the standard conversions it holds.

I think there will be a case where two implicit conversion sequences have its constituent standard conversion sequence steps which have different ranks each other. So, IMHO it is hard for me to determine which implicit conversion sequence is preferred than the other.

For example(Unfortunately, i couldn't come up with a concrete example.),

An implicit conversion sequence (A) consists of

  1. standard conversion sequence (A-1) which is rank promotion.
  2. no user-defined conversion sequence
  3. standard conversion sequence (A-2) which is rank conversion.

The other implicit conversion sequence (B) consists of

  1. standard conversion sequence (B-1) which is rank conversion.
  2. no user-defined conversion sequence
  3. standard conversion sequence (B-2) which is rank promotion.

In this case, A-1 is preferred than B-1 but B-2 is preferred than A-2. So, each of A and B have own preferences. -> ambiguous call?

OR... A-1 and B-1 should be compared first than A-2 and B-2. So, should we stop comparing each other here for greedy comparison? -> The A is chosen?


UPDATE: To explain my understanding about these concept...

// [ what is overall rank for standard coversion sequence n  ]
// [          standard conversion sequence n(up to 2)        ]
// [     each conversion's rank in a std conv sequence n     ]
// [ what conversions are performed in a std conv sequence n ]
// [    how source type T1 is converted to target type T2    ]

// [            promotion                ][       exact match    ]
// [          std conv seq1              ][     std conv seq2    ]
// [  promotion  |     exact match       ][        exact match   ]
// [  promotion  |  const qualification  ][     no conversion    ]
// [char   ->   int    ->   const int    ->        const int     ]
void f(const int){
    std::cout << "f(const int)" << std::endl;
}

// [   promotion   ][                conversion                  ]
// [ std conv seq1 ][               std conv seq2                ]
// [   promotion   ||      conversion      |     exact match     ]
// [   promotion   ||  integral conversion, const qualification  ]
// [char   ->     int       ->     long    ->    const long      ]
void f(const long){
    std::cout << "f(const long)" << std::endl;
}

int main() {
    // For the first sequence, the two functions have same 2nd rank, 'promotion'.
    // So, we couldn't determine which function will be called yet.
    // But, for the second sequence, the former has 1st rank 'exact match'
    // and the latter has 3rd rank 'conversion'. So the former will be called.
    f('c'); // prints "f(const int)"
}

CodePudding user response:

Cppreference is a useful reference site, but it is not the C standard. It has mostly accurate information, but in boiling down the complexities of the standard, some details can be lost around the margins.

I will be citing C 17 (since I don't have a C 11 website I can link to), but the wording has not meaningfully changed.

[over.best.ics]/3 defines an implicit conversion sequence as:

A well-formed implicit conversion sequence is one of the following forms:

  • a standard conversion sequence,
  • a user-defined conversion sequence, or
  • an ellipsis conversion sequence.

This is more-or-less what Cppreference says, but here it is made more explicit that you either have precisely one standard conversion sequence or you have precisely one user-defined conversion. The user-defined conversion itself includes two standard conversion sequences:

A user-defined conversion sequence consists of an initial standard conversion sequence followed by a user-defined conversion ([class.conv]) followed by a second standard conversion sequence.

Cppreference makes it seem like you can have two standard conversion sequences without a user-defined conversion, but you cannot. If there is no user-defined conversion in play, you have only one standard conversion.

Don't try to read Cppreference as the legal definition of C . Think of it more as "C works mostly like this". If you need legalistic detail (and in most cases, you don't. Especially around overload resolution. Knowing too much about this can make you a bad programmer), then you have to go to the standard.

  • Related