* ее второй аргумент имеет тот же ранг. К аргументу 'a' типа char для установления соответствия со вторым формальным параметром любой из двух функций должна быть применена последовательность преобразований, имеющая ранг расширения типа.
Вот еще один пример:
int compute( const int, short );
int compute( int, double );
extern int iobj;
int main() {
compute( iobj, 'c' ); // compute( int, double )
return 0;
}
Обе функции compute( const int, short ) и compute( int, double ) устояли. Вторая выбирается в качестве наилучшей по следующим причинам:
* ее первый аргумент лучше. Инициализация ссылки для первой устоявшей функции хуже потому, что она требует добавления спецификатора const, не нужного для второй функции;
ее второй аргумент имеет тот же ранг. К аргументу 'c' типа char для установления соответствия со вторым формальным параметром любой из двух функций должна быть применена последовательность трансформаций, имеющая ранг стандартного преобразования.
*
9.4.4. Аргументы со значениями по умолчанию
Наличие аргументов со значениями по умолчанию способно расширить множество устоявших функций. Устоявшими являются функции, которые вызываются с данным списком фактических аргументов. Но такая функция может иметь больше формальных параметров, чем задано фактических аргументов, в том случае, когда для каждого неуказанного параметра есть некое значение по умолчанию:
extern void ff( int );
extern void ff( long, int = 0 );
int main() {
ff( 2L ); // соответствует ff( long, 0 );
ff( 0, 0 ); // соответствует ff( long, int );
ff( 0 ); // соответствует ff( int );
ff( 3.14 ); // ошибка: неоднозначность
}
Для первого и третьего вызовов функция ff() является устоявшей, хотя передан всего один фактический аргумент. Это обусловлено следующими причинами:
* для второго формального параметра есть значение по умолчанию;
* первый параметр типа long точно соответствует фактическому аргументу в первом вызове и может быть приведен к типу аргумента в третьем вызове за счет последовательности, имеющей ранг стандартного преобразования.
Последний вызов является неоднозначным, поскольку обе устоявших функции могут быть выбраны, если применить стандартное преобразование к первому аргументу. Функции ff(int) не отдается предпочтение только потому, что у нее один параметр.
Объясните, что происходит при разрешении перегрузки для вызова функции compute() внутри main(). Какие функции являются кандидатами? Какие из них устоят после первого шага? Какие последовательности преобразований надо применить к фактическому аргументу, чтобы он соответствовал формальному параметру для каждой устоявшей функции? Какая функция будет наилучшей из устоявших?
namespace primerLib {
void compute();
void compute( const void * );
}
using primerLib::compute;
void compute( int );
void compute( double, double = 3.4 );
void compute( char*, char* = 0 );
int main() {
compute( 0 );
return 0;
}
Что будет, если using-объявление поместить внутрь main() перед вызовом compute()? Ответьте на те же вопросы.
10. Шаблоны функций