Понимание неоднозначных вызовов

Я пытался понять неоднозначные вызовы в приведенном ниже коде, но я не могу его понять. Три из них выдают ошибку.

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


Может кто-нибудь объяснить, как понять неоднозначный вызов?

Спасибо

Вы должны прочитать о разрешении перегрузки и о том, как ранжируются кандидаты на перегрузку. Ни для одного из трех вызовов нет точного совпадения, поэтому компилятор должен найти следующее наилучшее совпадение, и в каждом случае имеется более одного кандидата с одинаковым рангом, поэтому он не знает, какой из них вам нужен.

Super-intelligent Shade 30.07.2023 18:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
85
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как кто-то указал на это в теперь удаленном ответе, у 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.

Nicol Bolas 30.07.2023 18:55

Спасибо за ответ. Но я все равно не уследил. Я действительно видел это и пытался понять это. но это как-то запутанно. Может быть, вы можете объяснить это подробно (особенно последнее). Было бы очень полезно

Coder 30.07.2023 18:57

@Coder: «Но я все еще не понял». Что вы не уследили? Разве вы не видите, откуда берутся конверсии? За пределами случая № 3 этот ответ, кажется, адекватно объясняет ситуацию.

Nicol Bolas 30.07.2023 19:00

«все 3 кандидата эквивалентны, так как все они требуют 2 конверсий» Nitpick: Они не ранжируются по количеству конверсий. Чтобы одна перегрузка была лучше другой, она должна, грубо говоря, быть не хуже другой во всех аспектах (если перегрузке требуется преобразование для i-го параметра, она никогда не может быть лучше той, которая не 't), а затем лучше по крайней мере в одном аспекте.

HolyBlackCat 30.07.2023 21:23

@HolyBlackCat, ты прав. Я добавил обновление к ответу, чтобы исправить, что количество конверсий не имеет значения.

Super-intelligent Shade 30.07.2023 21:55

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