Почему компилятор может перегружать функции передачей по ссылке и передачей по значению
Я думал, что во время перегрузки компилятор проверяет, являются ли формальные аргументы одного и того же типа. Например:
void a(int x)
void a(double x)
может перегружаться просто потому, что два "х" имеют тип разности.
Однако существуют ли следующие два типа:
void f(int y)
void f(int& y)
Я понимаю, что это PBV и другой PBR. Но второй у имеет тип "int", а также правильно? Почему он успешно компилируется?
P.S.
Я замечаю, что, хотя он компилируется, он не работает, хотя и сообщает ошибку времени выполнения неоднозначности.
Ответы
Ответ 1
Функции в целом могут быть перегружены на основе:
- Число аргументов
- Тип аргументов
- Последовательность аргументов
Пример компилируется, потому что он удовлетворяет второму критерию.
int
и int &
- разные типы данных.
Рассмотрим следующий пример:
void foo(int i);
void foo(int& i);
void foo(int i){}
void foo(int& i){}
int main()
{
return 0;
}
Вышеприведенный код компилируется, потому что он действительный код. В зависимости от того, какой аргумент функции передается функции, компилятор может/не может определить наилучшее соответствие для вызова функции. Таким образом, сами функции могут сосуществовать, но их использование определенными способами может вызвать неоднозначность для компилятора.
Например:
В следующем коде литерал не может быть привязан к неконстантной ссылке, и поэтому единственным кандидатом на вызов функции является не ссылочная версия, и это должно компилироваться и работать очень хорошо:
void foo(int i);
void foo(int& i);
void foo(int i){}
void foo(int& i){}
int main()
{
foo(20);
return 0;
}
Но,
void foo(int i);
void foo(int& i);
void foo(int i){}
void foo(int& i){}
int main()
{
int i = 10;
foo(i);
return 0;
}
вышеуказанное вызовет неоднозначность для компилятора, поскольку компилятор не может определить наилучшее совпадение между двумя вызовами функций.
Ответ 2
Это зависит. Если вы не вызываете эти функции из своего кода, компилятор может их оптимизировать. Если это не так, вы можете открыть файл .obj с помощью средства просмотра текста и поиска имени функции (дайте ему более уникальное имя, чем f
, например floop
:-)), вы увидите два искалеченных имени используя ваше основное имя функции.
Но если вы попытаетесь их использовать, вы заметите разницу. Если вы вызываете
f(5);
Компилятор может использовать только версию f(int y)
, потому что невозможно передать константу по ссылке. Но если вы делаете
int b = 10;
f(b);
Затем компилятор выдает ошибку amibuity, так как обе формы f
могут быть вызваны таким образом.
Ответ 3
Возьмем вызов f (x), где x - int.
$13.3.3.1.4 - "Когда параметр ссылочного типа связывается напрямую (8.5.3) к выражению аргумента, неявная последовательность преобразования преобразование идентичности, если выражение аргумента не имеет типа это производный класс типа параметра, и в этом случае неявная последовательность преобразования представляет собой преобразование с производной базой"
Следовательно, f (int &) является точным совпадением, а также f (int), поскольку оба являются преобразованиями идентичности. Поэтому двусмысленность
Теперь возьмем вызов 'f (2)'
Это прекрасно, потому что 'f (int &)' не является совпадением вообще, поскольку rvalues не связывают с не-const lvalues. Поэтому никакая двусмысленность
Таким образом, стандарт позволяет 'f (T)' abd 'f (T &)' формировать набор перегрузки.
Ответ 4
Во-первых, неоднозначность всегда сообщается во время компиляции.
Во-вторых, независимо от того, будет ли ваш пример компилироваться или нет, зависит от того, как вы используете эту функцию.
void f(int y)
{
}
void f(int& y)
{
}
int main ()
{
int a = 10;
f (a); // ERROR: ambiguous call
f (10); // OK
}
В первом случае возникает ошибка, так как a
может быть передана как копия, так и ссылка.
Во втором случае ошибки не будет, потому что int
литерал не может быть передан неконстантной ссылкой