Я пытался понять неоднозначные вызовы в приведенном ниже коде, но я не могу его понять. Три из них выдают ошибку.
struct A {
virtual void func(int a, float b) const { std::cout << "a1" << std::endl; }
virtual void func(double a, float b) { std::cout << "a2" << std::endl; }
void func(unsigned int a, char b) { std::cout << "a3" << std::endl; }
};
int main() {
A baseObj;
baseObj.func(1, 1.0);//Error : expecting a1
baseObj.func(2, 2.0f);//Error : expecting a1
baseObj.func(3, 'c');//Error : expecting a3
return 0;
}
если я изменю его на:
baseObj.func(1.0, 1.0);//a2
baseObj.func(2.0, 2.0f);//a2
baseObj.func(3, 'c');//Error, if i remove unsigned from function, then it gives a3.
// I dont know what exactly happening here
Может кто-нибудь объяснить, как понять неоднозначный вызов?
Спасибо





Как кто-то указал на это в теперь удаленном ответе, у MSVC есть самое красноречивое объяснение:
<source>(13): error C2666: 'A::func': overloaded functions have similar conversions
<source>(7): note: could be 'void A::func(unsigned int,char)'
<source>(6): note: or 'void A::func(double,float)'
<source>(5): note: or 'void A::func(int,float) const'
<source>(13): note: while trying to match the argument list '(int, double)'
<source>(14): error C2666: 'A::func': overloaded functions have similar conversions
<source>(7): note: could be 'void A::func(unsigned int,char)'
<source>(6): note: or 'void A::func(double,float)'
<source>(5): note: or 'void A::func(int,float) const'
<source>(14): note: while trying to match the argument list '(int, float)'
<source>(14): note: note: qualification adjustment (const/volatile) may be causing the ambiguity
<source>(15): error C2666: 'A::func': overloaded functions have similar conversions
<source>(7): note: could be 'void A::func(unsigned int,char)'
<source>(6): note: or 'void A::func(double,float)'
<source>(5): note: or 'void A::func(int,float) const'
<source>(15): note: while trying to match the argument list '(int, char)'
Можете посмотреть сами здесь: https://godbolt.org/z/ee4E61d79
Теперь, почему это?
В первом вызове вы передаете int (1) и double (1.0) и ожидаете вызова a1. Однако для a1 требуется константный объект (из-за квалификатора const), int и float.
Таким образом, должны произойти два преобразования: baseObj должно быть «преобразовано» из A в const A и 1.0 должно быть преобразовано из double в float. Аналогично, a2 требует 2 преобразования — 1 в double и 1.0 в float. То же самое с a3 -- 1 в unsigned int и 1.0 в char.
С точки зрения компилятора все 3 кандидата эквивалентны, так как все они требуют преобразований. Таким образом, он не знает, какой из них он должен вызвать, и выдает ошибку.
Аналогичные вещи происходят во втором и третьем звонках.
ОБНОВЛЕНИЕ в ответ на комментарии.
Ранжирование по перегрузке — довольно сложный процесс, описанный в over.ics.rank. Пытаясь сделать свой ответ простым - и в надежде, что никто не заметит;), я немного упростил ситуацию.
Но, не тратя часы на копание в стандарте, насколько я могу судить, это то, что происходит:
Раздел 4 говорит, что последовательности преобразования упорядочены по их рангу. В 3-м вызове все 3 кандидата имеют одинаковый ранг — конверсия, потому что все они требуют конверсии.
NB: int -> unsigned int — это конверсия, а не продвижение.
Раздел 3.2 определяет, когда одна последовательность преобразования считается лучше другой. А последовательности одного ранга считаются неразличимыми (ни лучше, ни лучше) вне зависимости от количества преобразований.
Итак, вот почему 3-й (как и первые два) вызовы терпят неудачу.
Можете ли вы объяснить, почему № 3 терпит неудачу? Я вижу только одно преобразование, необходимое для вызова перегрузки a3: преобразование из int в unsigned int.
Спасибо за ответ. Но я все равно не уследил. Я действительно видел это и пытался понять это. но это как-то запутанно. Может быть, вы можете объяснить это подробно (особенно последнее). Было бы очень полезно
@Coder: «Но я все еще не понял». Что вы не уследили? Разве вы не видите, откуда берутся конверсии? За пределами случая № 3 этот ответ, кажется, адекватно объясняет ситуацию.
«все 3 кандидата эквивалентны, так как все они требуют 2 конверсий» Nitpick: Они не ранжируются по количеству конверсий. Чтобы одна перегрузка была лучше другой, она должна, грубо говоря, быть не хуже другой во всех аспектах (если перегрузке требуется преобразование для i-го параметра, она никогда не может быть лучше той, которая не 't), а затем лучше по крайней мере в одном аспекте.
@HolyBlackCat, ты прав. Я добавил обновление к ответу, чтобы исправить, что количество конверсий не имеет значения.
Вы должны прочитать о разрешении перегрузки и о том, как ранжируются кандидаты на перегрузку. Ни для одного из трех вызовов нет точного совпадения, поэтому компилятор должен найти следующее наилучшее совпадение, и в каждом случае имеется более одного кандидата с одинаковым рангом, поэтому он не знает, какой из них вам нужен.