Using-директивы также оказывают влияние на состав множества функций-кандидатов. Предположим, мы решили их использовать, чтобы сделать функции max() из пространства имен libs_R_us видимыми в func(). Если разместить следующую using-директиву в глобальной области видимости, то множество функций-кандидатов будет состоять из глобальной функции max(char, char) и функций max(int, int) и max(double, double), объявленных в libs_R_us:
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 )
}
Что будет, если поместить using-директиву в локальную область видимости, как в следующем примере?
void func()
{
// using-директива
using namespace libs_R_us;
// те же вызовы функций, что и выше
}
Какие из функций max() окажутся среди кандидатов? Напомним, что using-директива делает члены пространства имен видимыми, словно они были объявлены вне этого пространства, в той точке, где такая директива помещается. В нашем примере члены libs_R_us видимы в локальной области функции func(), как будто они объявлены вне пространства – в глобальной области. Отсюда следует, что множество перегруженных функций, видимых внутри func(), то же, что и раньше, т.е. включает в себя
max( char, char );
libs_R_us::max( int, int );
libs_R_us::max( double, double );
В локальной или глобальной области видимости появляется using-директива, на разрешение вызовов функции func() не влияет:
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 )
}
Итак, множество кандидатов состоит из функций, видимых в точке вызова, включая и те, которые введены using-объявлениями и using-директивами, а также из функций, объявленных в пространствах имен, ассоциированных с типами фактических аргументов. Например:
namespace 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) и f(double).
void f();
void f( int );
void f( double );
void f( char*, char* );
int main() {
f( 5.6 ); // 2 устоявшие функции: f( int ) и f( double )
return 0;
}