If no operand of an operator in an expression has a type that is a class or an enumeration, the operator is assumed to be a built-in operator and interpreted according to Clause [expr]. [ Note: Because ., .*, and :: cannot be overloaded, these operators are always built-in operators interpreted according to Clause [expr]. ?: cannot be overloaded, but the rules in this subclause are used to determine the conversions to be applied to the second and third operands when they have class or enumeration type ([expr.cond]). — end note ] [ Example:
struct String { String (const String&); String (const char*); operator const char* (); }; String operator + (const String&, const String&); void f(void) { 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 ]
If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator. In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator. Therefore, the operator notation is first transformed to the equivalent function-call notation as summarized in Table [tab:over.rel.op.func] (where @ denotes one of the operators covered in the specified subclause).
Subclause | Expression | As member function | As non-member function |
[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) |
For a unary operator @ with an operand of a type whose cv-unqualified version is T1, and for a binary operator @ with a left operand of a type whose cv-unqualified version is T1 and a right operand of a type whose cv-unqualified version is T2, three sets of candidate functions, designated member candidates, non-member candidates and built-in candidates, are constructed as follows:
If T1 is a complete class type or a class currently being defined, the set of member candidates is the result of the qualified lookup of T1::operator@ ([over.call.func]); otherwise, the set of member candidates is empty.
The set of non-member candidates is the result of the unqualified lookup of operator@ in the context of the expression according to the usual rules for name lookup in unqualified function calls ([basic.lookup.argdep]) except that all member functions are ignored. However, if no operand has a class type, only those non-member functions in the lookup set that have a first parameter of type T1 or “reference to (possibly cv-qualified) T1”, when T1 is an enumeration type, or (if there is a right operand) a second parameter of type T2 or “reference to (possibly cv-qualified) T2”, when T2 is an enumeration type, are candidate functions.
For the operator ,, the unary operator &, or the operator ->, the built-in candidates set is empty. For all other operators, the built-in candidates include all of the candidate operator functions defined in [over.built] that, compared to the given operator,
have the same operator name, and
accept the same number of operands, and
accept operand types to which the given operand or operands can be converted according to [over.best.ics], and
do not have the same parameter-type-list as any non-member candidate that is not a function template specialization.
For the built-in assignment operators, conversions of the left operand are restricted as follows:
no temporaries are introduced to hold the left operand, and
no user-defined conversions are applied to the left operand to achieve a type match with the left-most parameter of a built-in candidate.
For all other operators, no such restrictions apply.
The set of candidate functions for overload resolution is the union of the member candidates, the non-member candidates, and the built-in candidates. The argument list contains all of the operands of the operator. The best function from the set of candidate functions is selected according to [over.match.viable] and [over.match.best].129 [ 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 ]
If a built-in candidate is selected by overload resolution, the operands of class type are converted to the types of the corresponding parameters of the selected operation function, except that the second standard conversion sequence of a user-defined conversion sequence ([over.ics.user]) is not applied. Then the operator is treated as the corresponding built-in operator and interpreted according to Clause [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 ]
The second operand of operator -> is ignored in selecting an operator-> function, and is not an argument when the operator-> function is called. When operator-> returns, the operator -> is applied to the value returned, with the original second operand.130
If the operator is the operator ,, the unary operator &, or the operator ->, and there are no viable functions, then the operator is assumed to be the built-in operator and interpreted according to Clause [expr].
[ Note: The lookup rules for operators in expressions are different than the lookup rules for operator function names in a function call, as shown in the following example:
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 ]
If the set of candidate functions is empty, overload resolution is unsuccessful.
If the value returned by the operator-> function has class type, this may result in selecting and calling another operator-> function. The process repeats until an operator-> function returns a value of non-class type.