Фактический аргумент или формальный параметр функции могут быть ссылками. Как это влияет на правила преобразования типов?
Рассмотрим, что происходит, когда ссылкой является фактический аргумент. Его тип никогда не бывает ссылочным. Аргумент-ссылка трактуется как l-значение, тип которого совпадает с типом соответствующего объекта:
int i;
int& ri = i;
void print( int );
int main() {
print( i ); // аргумент - это lvalue типа int
print( ri ); // то же самое
return 0;
}
Фактический аргумент в обоих вызовах имеет тип int. Использование ссылки для его передачи во втором вызове не влияет на сам тип аргумента.
Стандартные преобразования и расширения типов, рассматриваемые компилятором, одинаковы для случаев, когда фактический аргумент является ссылкой на тип T и когда он сам имеет такой тип. Например:
int i;
int& ri = i;
void calc( double );
int main() {
calc( i ); // стандартное преобразование между целым типом
// и типом с плавающей точкой
calc( ri ); // то же самое
return 0;
}
А как влияет на преобразования, применяемые к фактическому аргументу, формальный параметр-ссылка? Сопоставление дает следующие результаты:
void swap( int &, int & );
void manip( int i1, int i2 ) {
// ...
swap( i1, i2 ); // правильно: вызывается swap( int &, int & )
// ...
return 0;
}
int obj;
void frd( double & );
int main() {
frd( obj ); // ошибка: параметр должен иметь иметь тип const double &
return 0;
}
Вызов функции frd() является ошибкой. Фактический аргумент имеет тип int и должен быть преобразован в тип double, чтобы соответствовать формальному параметру-ссылке. Результатом такой трансформации является временная переменная. Поскольку ссылка не имеет спецификатора const, то для ее инициализации такие переменные использовать нельзя.