13

Рассмотрим простой код:разрешение перегрузки с множеством функций и нескольких операторов преобразования

#include<iostream> 

struct A { 
    operator double(){ 
     std::cout<<"Conversion function double chosen."<<std::endl; 
     return 1.1; 
    } 
    operator char(){ 
     std::cout<<"Conversion function char chosen."<<std::endl; 
     return 'a'; 
    } 
} a; 

void foo(int){} 
void foo (char){} 
int main() { 
    foo(a); 
} 

Над кодом работает отлично, как и ожидалось GCC, лязг и VC++ выбирает foo(char).

Теперь позволяет изменить код немного:

#include<iostream> 

struct A { 
    operator double(){ 
     std::cout<<"Conversion function double chosen."<<std::endl; 
     return 1.1; 
    } 
    operator char(){ 
     std::cout<<"Conversion function char chosen."<<std::endl; 
     return 'a'; 
    } 
} a; 

void foo(int){} 
void foo (double){} //parameter changed from char to double 
int main() { 
    foo(a); 
} 

Теперь это должно иметь выбор foo(double), но, кажется, только VC++ счастлив с кодом, а лязг и НКУ недовольны выше кодом.

main.cpp:11:10: error: call of overloaded 'foo(A&)' is ambiguous 
foo(a); 
    ^
main.cpp:8:6: note: candidate: void foo(int) 
void foo(int){} 
    ^
main.cpp:9:6: note: candidate: void foo(double) 
void foo (double){} //parameter changed from char to double 
    ^

Может кто-нибудь объяснить, почему код выше не работает? или это ошибка ?.

Еще один вопрос: Содержит ли gcc и clang общий код разрешения перегрузки?

+2

1: Определите «несчастливые». 2: Что произойдет, если вы удалите 'foo (int)'? – Amit

+2

@Amit unhappy означает, что код отклоняется, а что касается удаления функции 'foo (int)', это не вопрос, вы можете попробовать его сами, пожалуйста. –

+1

@AngelusMortis: какая функция VC++ выбирает? – davidhigh

ответ

4

TL; DR: Разница заключается в том, что в первом случае, в отличие от второй, последовательности преобразования, определяемые пользователем (A -> char, A -> int) назвать ту же функцию преобразования (operator char). Это позволяет нам разорвать связь через [over.ics.rank]/(3.3).


Лучшие операторы преобразования для конкретных функций выбираются [over.match.best]/(1.4) (сравнения последовательностей преобразования их возвращаемых типов).

Поэтому лучше функция преобразования для foo(int)operator char является последующим продвижением к int, в отличие от operator double с последующим преобразованием с плавающей точкой.

Теперь рассмотрим оба варианта второй перегрузки:

  1. Лучшие ICS для foo(char) является также через operator char (тождественного лучше, чем преобразования с плавающей точкой).Таким образом, [over.ics.rank]/(3.3) применимо:

    определяемая пользователем последовательность U1 преобразования является лучшей последовательностью преобразования, чем другой заданной пользователем последовательности преобразования U2, если они содержат один и тот же определенный пользователем функцию преобразования [...] и в любом случае, вторая стандартная последовательность преобразования U1 лучше, чем вторая стандартная последовательность преобразования U2.

    Следовательно, общая конвертация в F2 считается лучше, и она выбрана.

  2. Лучший ICS для foo(double) является через operator double. В итоге мы получаем две последовательности преобразований, в которых используются различные функции преобразования; ничего действительно не применяется, и мы просто получаем двусмысленность.

5

A -> char является A -> char.

A -> int является A -> char -> int (потому что char к int является продвижение и так бьет преобразование double в int).

A -> double является A -> double.

Две пользовательские последовательности преобразования могут быть сопоставимы только в том случае, если они содержат одну и ту же пользовательскую функцию преобразования. Таким образом, A -> char является лучшей последовательностью преобразования, чем A -> int, поэтому ваш первый случай недвусмыслен. Ни A -> int, ни A -> double лучше, чем другой, поэтому второй случай неоднозначен.

 Смежные вопросы

  • Нет связанных вопросов^_^