Читать «Справочное руководство по C++» онлайн - страница 79

Бьярн Страустрап

 d = y; // вызов Y::operator double()

 float f = y; // ошибка: неоднозначность

}

Стандартные преобразования (§R.4) могут применяться к параметру, как до пользовательского преобразования, так и после него.

struct S { S(long); operator int();} ;

void f(long), f(char*);

void g(S), g(char*);

void h(const S&), h(char*);

void k(S& a)

{

 f(a); // f(long(a.operator int()))

 g(1); // g(S(long(1)))

 h(1); // h(S(long(1)))

}

Если для параметра требуется пользовательское преобразование, то не учитываются никакие стандартные преобразования, которые могут затрагивать этот параметр, например:

class x {

public:

 x(int);

};

class y {

public:

 y(long);

};

void f(x);

void f(y);

void g()

{

 f(1); // неоднозначность

}

Здесь вызов f(1) неоднозначен. Несмотря на то, что для вызова f(y(long(1))) требуется на одно стандартное преобразование больше, чем для вызова f(x(1)), второй вызов не является предпочтительным.

Преобразования с помощью конструктора (§R.12.1) и с помощью функции преобразования (§R.12.3.2) равноправны.

struct X {

 operator int();

};

struct Y {

 Y(X);

};

Y operator+(Y,Y);

void f(X a, X b)

{

 a+b; // ошибка, неоднозначность:

  // operator+(Y(a), Y(b)) или

  // a.operator int() + b.operator int()

}

R.13.3 Адрес перегруженной функции

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

• инициализируемый объект (§R.8.4);

• левая часть операции присваивания (§R.5.17);

• формальный параметр функции (§R.5.2.2);

• формальный параметр пользовательской операции (§R.13.4);

• тип значения, возвращаемого функцией (§R.8.2.5).

Отметим, что если f() и g() являются перегруженными функциями, то для правильной интерпретации f(&g) или эквивалентного выражения f(g) нужно рассмотреть пересечение множеств выбора для f() и g(). Приведем пример:

int f(double);

int f(int);

int (*pfd)(double) = &f;

int (*pfi)(int) = &f;

int (*pfe)(…) = &f; // ошибка: несоответствие типов

Последняя инициализация ошибочна, не из-за неоднозначности, а потому, что не определено ни одной функции f() типа int(…).

Отметим, что не существует никакого стандартного преобразования (§R.4) указателя на функцию одного типа в указатель на функцию другого типа (§R.4.6). В частности, даже если B является общим базовым классом D, две следующие инициализации недопустимы:

D* f();

B* (*p1)() =&f; // ошибка

void g(D*);

void (*p2)(B*) =&g; // ошибка

R.13.4 Перегруженные операции

Перегружать можно большинство операций.