2011-12-31 3 views
4
#include <iostream> 
#include <cmath> 
using namespace std; 

float f (int a, int b) { 
    return (a + b); 
} 

float f (float a, float b) { 
    return (round(a + b)); 
} 

int main() 
{ 
    cout << "Hello World!" << endl; 
    int int1 = 1; 
    int int2 = 2; 
    float float1 = 1.2f; 
    float float2 = 1.4f; 
    cout << f(int1, int2) << endl;  // output: 3 
    cout << f(float1, float2) << endl; // output: 2 
    cout << f(int1, float2) << endl; // output: 2 
    return 0; 
} 
  1. Почему последний выход использует второе определение f?Как определить, какая перегруженная функция называется?

  2. В целом, как определить, какое перегруженное определение функции будет использоваться, когда точное определение количества и типов аргументов между определениями функций и вызовом функции не выполняется?

+1

Я думаю, что вы имели в виду: 'float float1 = 1.2;' и 'float float2 = 1.4;' – Mysticial

+0

Мой прямой ответ будет заключаться в том, что 'int -> float' является лучшим преобразованием, чем' float -> int'. Интересно, что мне не удалось найти цитату в стандарте, где это указано. –

+0

Какой компилятор/версия вы используете? После проверки стандарта я считаю, что код должен вызывать ошибку, поскольку вызов 'f (int1, float2)' is * неоднозначный *. GCC и Clang согласны. –

ответ

4

После попытки определить в стандарте, почему одна перегрузка предпочтительна по сравнению с другой, я пришел к выводу, что она не должна, никакая перегрузка не имеет лучшей последовательности преобразования, чем другая в случае f(int1, float2), а код должен не компилировать. Если ваш компилятор принимает его, может быть ошибка в реализации.

По второму вопросу, стандарт определяет преобразования, которые могут быть использованы, чтобы соответствовать вызов функции, и это также определяет ранг для тех переходов, который служит в качестве частичного упорядочения (так называемый лучше преобразования, чем). Компилятор всегда будет выбирать лучший вариант, а если нет , то лучше всего преобразование, то программа плохо сформирована, как в примере.

Проверка неоднозначности кода с разными компиляторами:

GCC:

conv.cpp:22: error: call of overloaded ‘f(int&, float&)’ is ambiguous 
conv.cpp:5: note: candidates are: float f(int, int) 
conv.cpp:9: note:     float f(float, float) 

лязг:

conv.cpp:22:13: error: call to 'f' is ambiguous 
    cout << f(int1, float2) << endl; // output: 2 
      ^
conv.cpp:5:7: note: candidate function 
float f (int a, int b) { 
    ^
conv.cpp:9:7: note: candidate function 
float f (float a, float b) { 
    ^

МСВС 2010 (Спасибо Xeo):

error C2666: 'f' : 2 overloads have similar conversions 
      src\main.cpp(2): could be 'void f(int,int)' 
      src\main.cpp(1): or  'void f(float,float)' 
      while trying to match the argument list '(int, float)' 
+0

+1, вы можете добавить MSVC10 к компиляторам, отклоняющим код, [вот сообщение об ошибке] (http://ideone.com/juukz). – Xeo

0

Все, что нужно знать и больше: http://www.learncpp.com/cpp-tutorial/76-function-overloading/

По существу, второй один выбран потому, что, если нет точного совпадения не возможно и не соответствуют друг другу по продвижению не возможно, совпадение путем преобразования (первого параметра от int до float) делается.

+0

Теперь вопрос в том, где в стандарте преобразование 'int-> float' считается лучшей последовательностью преобразования, чем преобразование' float-> int', оба из которых являются * конверсиями с плавающим интегралом * –

+0

Я сомневаюсь, что float-> int считается лучше, так как вы теряете информацию. – Tudor

+0

Мы согласны с тем, что нет смысла рассматривать лучшее преобразование, которое может потенциально потерять информацию, но это, вероятно, определено где-то в стандарте, который я не смог найти. –

0

В очень простых выражениях, если вы конвертируете int в float, вы не теряете никакой информации; если вы конвертируете float в int, вы теряете десятичную часть номера. Если компилятор не может найти точное совпадение перегрузки, он выберет тот, который вызывает наименьшую потерю информации.

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