void putValues(const int *);

int main() {

putValues(arr); // необходимо 2 преобразования

// массив в указатель + преобразование спецификатора

return 0;

}

для приведения аргумента arr от типа “массив из трех int” к типу “указатель на const int” применяется последовательность преобразований:

* Преобразование массива в указатель, которое трансформирует массив из трех int в указатель на int.

* Преобразование спецификатора, которое трансформирует указатель на int в указатель на const int.

Поэтому было бы более правильно говорить, что для приведения фактического аргумента к типу формального параметра устоявшей функции требуется последовательность преобразований. Поскольку применяется не одна, а несколько трансформаций, то на третьем шаге процесса разрешения перегрузки функции на самом деле ранжируются последовательности преобразований.

Рангом такой последовательности считается ранг самой плохой из входящих в нее трансформаций. Как объяснялось в разделе 9.2, преобразования типов ранжируются следующим образом: точное соответствие лучше расширения типа, а расширение типа лучше стандартного преобразования. В предыдущем примере оба изменения имеют ранг точного соответствия. Поэтому и у всей последовательности такой же ранг.

Такая совокупность состоит из нескольких преобразований, применяемых в указанном порядке:

преобразование l-значения -

расширение типа или стандартное преобразование -

преобразование спецификаторов

Термин преобразование l-значения относится к первым трем трансформациям из категории точных соответствий, рассмотренных в разделе 9.2: преобразование l-значения в r-значение, преобразование массива в указатель и преобразование функции в указатель. Последовательность трансформаций состоит из нуля или одного преобразования l-значения, за которым следует нуль или одно расширение типа или стандартное преобразование, и наконец нуль или одно преобразование спецификаторов. Для приведения фактического аргумента к типу формального параметра может быть применено только одна трансформация каждого вида.

Описанная последовательность называется последовательностью стандартных преобразований. Существует также последовательность определенных пользователем преобразований, которая связана с функцией-конвертером, являющейся членом класса. (Конвертеры и последовательности определенных пользователем преобразований рассматриваются в главе 15.)

Каковы последовательности изменений фактических аргументов в следующем примере?

namespace libs_R_us {

int max( int, int );

double max( double, double );

}

// using-объявление

using libs_R_us::max;

void func()

{

char c1, c2;

max( c1, c2 ); // вызывается libs_R_us::max( int, int )

}

Аргументы в вызове функции max() имеют тип char. Последовательность преобразований аргументов при вызове функции libs_R_us::max(int,int) следующая:

1a. Так как аргументы передаются по значению, то с помощью преобразования l-значения в r-значение извлекаются значения аргументов c1 и c2.

2a. С помощью расширения типа аргументы трансформируются из char в int.

Последовательность преобразований аргументов при вызове функции libs_R_us::max(double,double) следующая:

1b. С помощью преобразования l-значения в r-значение извлекаются значения аргументов c1 и c2.

2b. Стандартное преобразование между целым и плавающим типом приводит аргументы от типа char к типу double.

Ранг первой последовательности – расширение типа (самое худшее из примененных изменений), тогда как ранг второй – стандартное преобразование. Так как расширение типа лучше, чем преобразование, то в качестве наилучшей из устоявших для данного вызова выбирается функция libs_R_us::max(int,int).

Если ранжирование последовательностей преобразований аргументов не может выявить единственной устоявшей функции, то вызов считается неоднозначным. В данном примере для обоих вызовов calc() требуется такая последовательность:

* Преобразование l-значения в r-значение для извлечения значений аргументов i и j.

* Стандартное преобразование для приведения типов фактических аргументов к типам соответствующих формальных параметров.

Поскольку нельзя сказать, какая из этих последовательностей лучше другой, вызов неоднозначен:

int i, j;

extern long calc( long, long );

extern double calc( double, double );

void jj() {

// ошибка: неоднозначность, нет наилучшего соответствия

calc( i, j );

}

Перейти на страницу:

Похожие книги