Преобразования типов аргументов *
На втором шаге процесса разрешения перегрузки функции компилятор идентифицирует и ранжирует преобразования, которые следует применить к каждому фактическому аргументу вызванной функции для приведения его к типу соответствующего формального параметра любой из устоявших функций. Ранжирование может дать один из трех возможных результатов:
- точное соответствие. Тип фактического аргумента точно соответствует типу формального параметра. Например, если в множестве перегруженных функций print() есть такие:
- соответствие с
преобразованием типа. Тип фактического аргумента не соответствует типу формального параметра, но может быть преобразован в него:
- отсутствие соответствия. Тип фактического аргумента не может быть приведен к типу формального параметра в объявлении функции, поскольку необходимого преобразования не существует. Для каждого из следующих двух вызовов функции print() соответствия нет:
- преобразование l-значения в r-значение;
- преобразование массива в указатель;
- преобразование функции в указатель;
- преобразования спецификаторов.
void print( unsigned int );
void print( const char* );
void print( char );
то каждый из следующих трех вызовов дает точное соответствие:
unsigned int a;
print( 'a' ); // соответствует print( char );
print( "a" ); // соответствует print( const char* );
print( a ); // соответствует print( unsigned int );
void ff( char );
ff( 0 ); // аргумент типа int приводится к типу char
// функции print() объявлены так же, как и выше
int *ip;
class SmallInt { /* ... */ };
SmallInt si;
print( ip ); // ошибка: нет соответствия
print( si ); // ошибка: нет соответствия
Для установления точного соответствия тип фактического аргумента необязательно должен совпадать с типом формального параметра. К аргументу могут быть применены некоторые тривиальные преобразования, а именно:
(Подробнее они рассмотрены ниже.)
Категория соответствия с преобразованием типа является наиболее сложной. Необходимо рассмотреть несколько видов такого приведения: расширение типов
(promotions), стандартные преобразования и определенные пользователем преобразования. (Расширения типов и стандартные преобразования изучаются в этой главе. Определенные пользователем преобразования будут представлены позднее, после детального рассмотрения классов; они выполняются конвертером, функцией-членом, которая позволяет определить в классе собственный набор “стандартных” трансформаций. В главе 15 мы познакомимся с такими конвертерами и с тем, как они влияют на разрешение перегрузки функций.)
При выборе лучшей из устоявших функций для данного вызова компилятор ищет функцию, для которой применяемые к фактическим аргументам преобразования являются “наилучшими”. Преобразования типов ранжируются следующим образом: точное соответствие лучше расширения типа, расширение типа лучше стандартного преобразования, а оно, в свою очередь, лучше определенного пользователем преобразования. Мы еще вернемся к ранжированию в разделе 9.4, а пока на простых примерах покажем, как оно помогает выбрать наиболее подходящую функцию.