С.Б. Липпман, Ж. Лажойе - Язык программирования С++ Вводный курс (1114944), страница 77
Текст из файла (страница 77)
такие, которые не скрыты при вызове. Вследующем примере функциями-кандидатами, видимыми в точке вызова, являютсяchar* format( int );void g() {char *format( double );char* format( char* );format(3);// вызывается format( double )format(double) и format(char*):}Так как format(int), объявленная в глобальной области видимости, скрыта, она невключается в множество функций-кандидатов.Кандидаты могут быть введены с помощью using-объявлений, видимых в точке вызова:С++ для начинающих455namespace libs_R_us {int max( int, int );double max( double, double );}char max( char, char );void func(){// функции из пространства имен невидимы// все три вызова разрешаются в пользу глобальной функции max( char,char )max( 87, 65 );max( 35.5, 76.6 );max( 'J', 'L' );}Функции max(), определенные в пространстве имен libs_R_us, невидимы в точкевызова. Единственной видимой является функция max() из глобальной области; толькоона входит в множество функций-кандидатов и вызывается при каждом из трехобращений к func().
Мы можем воспользоваться using-объявлением, чтобы сделатьвидимыми функции max() из пространства имен libs_R_us. Куда поместить using-char max( char, char );объявление? Если включить его в глобальную область видимости:using libs_R_us::max;// using-объявлението функции max() из libs_R_us добавляются в множество перегруженных функций,которое уже содержит max(), объявленную в глобальной области. Теперь все трифункции видны внутри func() и становятся кандидатами. В этой ситуации вызовыvoid func(){max( 87, 65 );// вызывается libs_R_us::max( int, int )max( 35.5, 76.6 ); // вызывается libs_R_us::max( double, double )max( 'J', 'L' );// вызывается ::max( char, char )func() разрешаются следующим образом:}Но что будет, если мы введем using-объявление в локальную область видимости функцииvoid func(){// using-объявлениеusing libs_R_us::max;// те же вызовы функций, что и вышеfunc(), как показано в данном примере?}С++ для начинающих456Какие из функций max() будут включены в множество кандидатов? Напомним, что usingобъявления вкладываются друг в друга.
При наличии такого объявления в локальнойобласти глобальная функция max(char, char) оказывается скрытой, так что в точкеlibs_R_us::max( int, int );вызова видны толькоlibs_R_us::max( double, double );void func(){// using-объявление// глобальная функция max( char, char ) скрытаusing libs_R_us::max;max( 87, 65 );// вызывается libs_R_us::max( int, int )max( 35.5, 76.6 ); // вызывается libs_R_us::max( double, double )max( 'J', 'L' );// вызывается libs_R_us::max( int, int )Они и являются кандидатами. Теперь вызовы func() разрешаются следующим образом:}Using-директивы также оказывают влияние на состав множества функций-кандидатов.Предположим, мы решили их использовать, чтобы сделать функции max() изпространства имен libs_R_us видимыми в func().
Если разместить следующую usingдирективу в глобальной области видимости, то множество функций-кандидатов будетсостоять из глобальной функции max(char, char) и функций max(int, int) иnamespace libs_R_us {int max( int, int );double max( double, double );}char max( char, char );using namespace libs_R_us;// using-директиваvoid func(){max( 87, 65 );// вызывается libs_R_us::max( int, int )max( 35.5, 76.6 ); // вызывается libs_R_us::max( double, double )max( 'J', 'L' );// вызывается ::max( int, int )max(double, double), объявленных в libs_R_us:}Что будет, если поместить using-директиву в локальную область видимости, как вследующем примере?С++ для начинающихvoid func(){// using-директиваusing namespace libs_R_us;// те же вызовы функций, что и выше}Какие из функций max() окажутся среди кандидатов? Напомним, что using-директиваделает члены пространства имен видимыми, словно они были объявлены вне этогопространства, в той точке, где такая директива помещается.
В нашем примере членыlibs_R_us видимы в локальной области функции func(), как будто они объявлены внепространства – в глобальной области. Отсюда следует, что множество перегруженныхmax( char, char );libs_R_us::max( int, int );функций, видимых внутри func(), то же, что и раньше, т.е. включает в себяlibs_R_us::max( double, double );В локальной или глобальной области видимости появляется using-директива, наvoid func(){using namespace libs_R_us;max( 87, 65 );// вызывается libs_R_us::max( int, int )max( 35.5, 76.6 ); // вызывается libs_R_us::max( double, double )max( 'J', 'L' );// вызывается ::max( int, int )разрешение вызовов функции func() не влияет:}Итак, множество кандидатов состоит из функций, видимых в точке вызова, включая и те,которые введены using-объявлениями и using-директивами, а также из функций,объявленных в пространствах имен, ассоциированных с типами фактических аргументов.Например:457С++ для начинающих458namespace basicLib {int print( int );double print( double );}namespace matrixLib {class matrix { /* ...
*/ };void print( const maxtrix & );}void display(){using basicLib::print;matrixLib::matrix mObj;print( mObj );// вызывается maxtrixLib::print( const maxtrix & )print( 87 );// вызывается basicLib::print( const maxtrix & )}Кандидатами для print(mObj) являются введенные using-объявлением внутриdisplay() функции basicLib::print(int) и basicLib::print(double), посколькуони видимы в точке вызова. Так как фактический аргумент функции имеет типmatrixLib::matrix, то функция print(), объявленная в пространстве имен matrixLib,также будет кандидатом. Каковы функции-кандидаты для print(87)? ТолькоbasicLib::print(int) и basicLib::print(double), видимые в точке вызова.Поскольку аргумент имеет тип int, дополнительное пространство имен в поисках другихкандидатов не рассматривается.9.4.2. Устоявшие функцииУстоявшая функция относится к числу кандидатов.
В списке ее формальных параметровлибо то же самое число элементов, что и в списке фактических аргументов вызваннойфункции, либо больше. В последнем случае для дополнительных параметров задаютсязначения по умолчанию, иначе функцию нельзя будет вызвать с данным числомаргументов. Чтобы функция считалась устоявшей, должно существовать преобразованиекаждого фактического аргумента в тип соответствующего формального параметра.(Такие преобразования были рассмотрены в разделе 9.3.)В следующем примере для вызова f(5.6) есть две устоявшие функции: f(int) иvoidvoidvoidvoidf();f( int );f( double );f( char*, char* );int main() {f( 5.6 );return 0;// 2 устоявшие функции: f( int ) и f( double )f(double).}Функция f(int) устояла, так как она имеет всего один формальный параметр, чтосоответствует числу фактических аргументов в вызове.
Кроме того, существуетстандартное преобразование аргумента типа double в int. Функция f(double) такжеС++ для начинающихустояла; она тоже имеет один параметр типа double, и он точно соответствуетфактическому аргументу. Функции-кандидаты f() и f(char*, char*) исключены изсписка устоявших, так как они не могут быть вызваны с одним аргументом.В следующем примере единственной устоявшей функцией для вызова format(3)является format(double).
Хотя кандидата format(char*) можно вызывать с однимаргументом, не существует преобразования из типа фактического аргумента int в типchar* format( int );void g() {// глобальная функция format( int ) скрытаchar* format( double );char* format( char* );format(3);// есть только одна устоявшая функция: format( double )формального параметра char*, а следовательно, функция не может считаться устоявшей.}В следующем примере все три функции-кандидата оказываются устоявшими для вызоваmax() внутри func(). Все они могут быть вызваны с двумя аргументами. Посколькуфактические аргументы имеют тип int, они точно соответствуют формальнымпараметрам функции libs_R_us::max(int, int) и могут быть приведены к типампараметров функции libs_R_us::max(double, double) с помощью трансформациицелых в плавающие, а также к типам параметров функции libs_R_us::max(char,namespace libs_R_us {int max( int, int );double max( double, double );}// using-объявлениеusing libs_R_us::max;char max( char, char );void func(){// все три функции max() являются устоявшимиmax( 87, 65 );// вызывается using libs_R_us::max( int, int )char) посредством преобразования целых типов.}Обратите внимание, что функция-кандидат с несколькими параметрами исключается изчисла устоявших, как только выясняется, что один из фактических аргументов не можетбыть приведен к типу соответствующего формального параметра, пусть даже для всехостальных аргументов такое преобразование существует.
В следующем примере функцияmin(char *, int) исключается из множества устоявших, поскольку нет возможноститрансформации типа первого аргумента int в тип соответствующего параметра char *.И это происходит несмотря на то, что второй аргумент точно соответствует второмупараметру.459С++ для начинающихextern double min( double, double );extern double min( char*, int );void func(){// одна функция-кандидат min( double, double )min( 87, 65 );// вызывается min( double, double )}Если после исключения из множества кандидатов всех функций с несоответствующимчислом параметров и тех, для параметров которых не оказалось подходящегопреобразования, не осталось устоявших, то обработка вызова функции заканчиваетсяvoid print( unsigned int );void print( char* );void print( char );int *ip;class SmallInt { /* ...
*/ };SmallInt si;int main() {print( ip );// ошибка: нет устоявших функций: соответствие ненайденоprint( si );// ошибка: нет устоявших функций: соответствие ненайденоreturn 0;ошибкой компиляции. В таком случае говорят, что соответствия не найдено.}9.4.3.
Наилучшая из устоявших функцияНаилучшей считается та из устоявших функций, формальные параметры которойнаиболее точно соответствуют типам фактических аргументов. Для любой такой функциипреобразования типов, применяемые к каждому аргументу, ранжируются дляопределения степени его соответствия параметру. (В разделе 6.2 описаныподдерживаемые преобразования типов.) Наилучшей из устоявших называют функцию,для которой одновременно выполняются два условия:•преобразования, примененные к аргументам, не хуже преобразований,необходимых для вызова любой другой устоявшей функции;•хотя бы для одного аргумента примененное преобразование лучше, чем для тогоже аргумента в любой другой устоявшей функции.Может оказаться так, что для приведения фактического аргумента к типусоответствующего формального параметра нужно выполнить несколько преобразований.Так, в следующем примере460С++ для начинающих461int arr[3];void putValues(const int *);int main() {putValues(arr);// необходимо 2 преобразования// массив в указатель + преобразование спецификатораreturn 0;}для приведения аргумента arr от типа “массив из трех int” к типу “указатель на constint” применяется последовательность преобразований:1.
Преобразование массива в указатель, которое трансформирует массив из трех int вуказатель на int.2. Преобразование спецификатора, которое трансформирует указатель на int вуказатель на const int.Поэтому было бы более правильно говорить, что для приведения фактического аргументак типу формального параметра устоявшей функции требуется последовательностьпреобразований.