16 Overloading [over]

16.3 Overload resolution [over.match]

16.3.1 Candidate functions and argument lists [over.match.funcs]

16.3.1.2 Operators in expressions [over.match.oper]

Если ни один из операндов оператора в выражении не имеет типа, который является классом или перечислением, предполагается, что оператор является встроенным оператором и интерпретируется в соответствии с Clause [expr]. [ Note: Поскольку ., .*и ​::​ не могут быть перегружены, эти операторы всегда являются встроенными операторами, интерпретируемыми в соответствии с пунктом [expr]. ?: не может быть перегружен, но правила в этом подпункте используются для определения преобразований, которые будут применяться ко второму и третьему операндам, если они имеют тип класса или перечисления ([expr.cond]). ] [end noteExample:

struct String {
  String (const String&);
  String (const char*);
  operator const char* ();
};
String operator + (const String&, const String&);

void f() {
 const char* p= "one" + "two";  // ill-formed because neither operand has class or enumeration type
 int I = 1 + 1;                 // always evaluates to 2 even if class or enumeration types exist
                                // that would perform the operation.
}

end example]

Если какой-либо из операндов имеет тип, который является классом или перечислением, может быть объявлена ​​пользовательская операторная функция, реализующая этот оператор, или может потребоваться пользовательское преобразование для преобразования операнда в тип, подходящий для встроенного в операторе. В этом случае разрешение перегрузки используется, чтобы определить, какую операторную функцию или встроенный оператор следует вызывать для реализации оператора. Следовательно, обозначение оператора сначала преобразуется в эквивалентное обозначение вызова функции, как показано в таблице 12 (где @ обозначает один из операторов, описанных в указанном подпункте). Однако операнды располагаются в порядке, установленном для встроенного оператора (пункт [expr]).

Таблица 12 - Связь между оператором и обозначением вызова функции
Подпункт Выражение Как функция-член Как функция, не являющаяся членом
[over.unary] @a (a).operator@ () operator@(a)
[over.binary] a@b (a).operator@ (b) operator@(a, b)
[over.ass] a=b (a).operator= (b)
[over.sub] a[b] (a).operator[](b)
[over.ref] a-> (a).operator->()
[over.inc] a@ (a).operator@ (0) operator@(a, 0)

Для унарного оператора @ с операндом типа, чья cv-неквалифицированная версия равна T1, и для бинарного оператора @ с левым операндом типа, чья cv-неквалифицированная версия есть, T1 и правым операндом типа, чья cv-неквалифицированная версия равна T2, три наборы кандидатов функций, обозначены member candidates, non-member candidates и built-in candidates, строятся следующим образом :

  • Если T1 это полный тип класса или класс, определяемый в настоящее время, набор кандидатов в члены является результатом квалифицированного поиска T1​::​operator@ ([over.call.func]); в противном случае набор кандидатов в члены пуст.

  • Набор кандидатов, не являющихся членами, является результатом неквалифицированного поиска operator@ в контексте выражения в соответствии с обычными правилами поиска имени в неквалифицированных вызовах функций ([basic.lookup.argdep]), за исключением того, что все функции-члены игнорируются. Однако, если ни один операнд не имеет типа класса, только те функции, не являющиеся членами в наборе подстановки, которые имеют первый параметр типа T1 или «ссылку на cv T1», когда T1 это тип перечисления или (если есть правый операнд) второй Параметр типа T2 или «ссылка на cv T2», когда T2 является типом перечисления, являются функциями-кандидатами.

  • Для оператора ,, унарного оператора &или оператора ->набор встроенных кандидатов пуст. Для всех других операторов встроенные кандидаты включают в себя все функции операторов-кандидатов, определенные в [over.built] этом, по сравнению с данным оператором,

    • иметь то же имя оператора и

    • принять такое же количество операндов и

    • принимать типы операндов, в которые можно преобразовать данный операнд или операнды в соответствии с [over.best.ics], и

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

Для встроенных операторов присваивания преобразование левого операнда ограничено следующим образом:

  • не вводятся временные файлы для хранения левого операнда, и

  • к левому операнду не применяются определяемые пользователем преобразования для достижения соответствия типа самому левому параметру встроенного кандидата.

Для всех остальных операторов такие ограничения отсутствуют.

Набор функций-кандидатов для разрешения перегрузки - это объединение кандидатов в члены, кандидатов, не являющихся членами, и встроенных кандидатов. Список аргументов содержит все операнды оператора. Лучшая функция из набора функций-кандидатов выбирается в соответствии с [over.match.viable] и [over.match.best].128 [Example:

struct A {
  operator int();
};
A operator+(const A&, const A&);
void m() {
  A a, b;
  a + b;                        // operator+(a, b) chosen over int(a) + int(b)
}

end example]

Если встроенный кандидат выбран путем разрешения перегрузки, операнды типа класса преобразуются в типы соответствующих параметров выбранной функции операции, за исключением того, что вторая стандартная последовательность преобразования a user-defined conversion sequence не применяется. Затем оператор рассматривается как соответствующий встроенный оператор и интерпретируется в соответствии с пунктом [expr]. [Example:

struct X {
  operator double();
};

struct Y {
  operator int*();
};

int *a = Y() + 100.0;           // error: pointer arithmetic requires integral operand
int *b = Y() + X();             // error: pointer arithmetic requires integral operand

end example]

Второй операнд оператора -> игнорируется при выборе operator-> функции и не является аргументом при operator-> вызове функции. При operator-> возврате оператор -> применяется к возвращенному значению с исходным вторым операндом.129

Если оператор является оператором ,, унарным оператором &или оператором ->и нет жизнеспособных функций, то предполагается, что оператор является встроенным оператором и интерпретируется в соответствии с пунктом [expr].

[ Note: Правила поиска для операторов в выражениях отличаются от правил поиска для имен операторных функций в вызове функции, как показано в следующем примере:

struct A { };
void operator + (A, A);

struct B {
  void operator + (B);
  void f ();
};

A a;

void B::f() {
  operator+ (a,a);              // error: global operator hidden by member
  a + a;                        // OK: calls global operator+
}

end note]

Если набор функций-кандидатов пуст, разрешение перегрузки не выполняется.

Если значение, возвращаемое operator-> функцией, имеет тип класса, это может привести к выбору и вызову другой operator-> функции. Процесс повторяется до тех пор, пока operator-> функция не вернет значение неклассового типа.