13 Overloading [over]

13.5 Overloaded operators [over.oper]

A function declaration having one of the following operator-function-ids as its name declares an operator function. A function template declaration having one of the following operator-function-ids as its name declares an operator function template. A specialization of an operator function template is also an operator function. An operator function is said to implement the operator named in its operator-function-id.

operator-function-id:
    operator operator
operator: one of
	new	delete	new[]	delete[]
	+	-	*	/	%	^	&	|	~
	!	=	<	>	+=	-=	*=	/=	%=
	^=	&=	|=	<<	>>	>>=	<<=	==	!=
	<=	>=	&&	||	++	--	,	->*	->
	( )	[ ]

Note: The last two operators are function call ([expr.call]) and subscripting ([expr.sub]). The operators new[], delete[], (), and [] are formed from more than one token.  — end note ]

Both the unary and binary forms of

+    -    *     &

can be overloaded.

The following operators cannot be overloaded:

.    .*   ::    ?:

nor can the preprocessing symbols # and ## (Clause [cpp]).

Operator functions are usually not called directly; instead they are invoked to evaluate the operators they implement ([over.unary][over.inc]). They can be explicitly called, however, using the operator-function-id as the name of the function in the function call syntax ([expr.call]). [ Example:

complex z = a.operator+(b);     // complex z = a+b;
void* p = operator new(sizeof(int)*n);

 — end example ]

The allocation and deallocation functions, operator new, operator new[], operator delete and operator delete, are described completely in [basic.stc.dynamic]. The attributes and restrictions found in the rest of this subclause do not apply to them unless explicitly stated in [basic.stc.dynamic].

An operator function shall either be a non-static member function or be a non-member function that has at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration. It is not possible to change the precedence, grouping, or number of operands of operators. The meaning of the operators =, (unary) &, and , (comma), predefined for each type, can be changed for specific class and enumeration types by defining operator functions that implement these operators. Operator functions are inherited in the same manner as other base class functions.

The identities among certain predefined operators applied to basic types (for example, ++a a+=1) need not hold for operator functions. Some predefined operators, such as +=, require an operand to be an lvalue when applied to basic types; this is not required by operator functions.

An operator function cannot have default arguments ([dcl.fct.default]), except where explicitly stated below. Operator functions cannot have more or fewer parameters than the number required for the corresponding operator, as described in the rest of this subclause.

Operators not mentioned explicitly in subclauses [over.ass] through [over.inc] act as ordinary unary and binary operators obeying the rules of [over.unary] or [over.binary].

13.5.1 Unary operators [over.unary]

A prefix unary operator shall be implemented by a non-static member function ([class.mfct]) with no parameters or a non-member function with one parameter. Thus, for any prefix unary operator @, @x can be interpreted as either x.operator@() or operator@(x). If both forms of the operator function have been declared, the rules in [over.match.oper] determine which, if any, interpretation is used. See [over.inc] for an explanation of the postfix unary operators ++ and --.

The unary and binary forms of the same operator are considered to have the same name. [ Note: Consequently, a unary operator can hide a binary operator from an enclosing scope, and vice versa.  — end note ]

13.5.2 Binary operators [over.binary]

A binary operator shall be implemented either by a non-static member function ([class.mfct]) with one parameter or by a non-member function with two parameters. Thus, for any binary operator @, x@y can be interpreted as either x.operator@(y) or operator@(x,y). If both forms of the operator function have been declared, the rules in [over.match.oper] determine which, if any, interpretation is used.

13.5.3 Assignment [over.ass]

An assignment operator shall be implemented by a non-static member function with exactly one parameter. Because a copy assignment operator operator= is implicitly declared for a class if not declared by the user ([class.copy]), a base class assignment operator is always hidden by the copy assignment operator of the derived class.

Any assignment operator, even the copy and move assignment operators, can be virtual. [ Note: For a derived class D with a base class B for which a virtual copy/move assignment has been declared, the copy/move assignment operator in D does not override B's virtual copy/move assignment operator. [ Example:

struct B {
  virtual int operator= (int);
  virtual B& operator= (const B&);
};
struct D : B {
  virtual int operator= (int);
  virtual D& operator= (const B&);
};

D dobj1;
D dobj2;
B* bptr = &dobj1;
void f() {
  bptr->operator=(99);          // calls D::operator=(int)
  *bptr = 99;                   // ditto
  bptr->operator=(dobj2);       // calls D::operator=(const B&)
  *bptr = dobj2;                // ditto
  dobj1 = dobj2;                // calls implicitly-declared
                                // D::operator=(const D&)
}

 — end example ]  — end note ]

13.5.4 Function call [over.call]

operator() shall be a non-static member function with an arbitrary number of parameters. It can have default arguments. It implements the function call syntax

postfix-expression ( expression-listopt )

where the postfix-expression evaluates to a class object and the possibly empty expression-list matches the parameter list of an operator() member function of the class. Thus, a call x(arg1,...) is interpreted as x.operator()(arg1, ...) for a class object x of type T if T::operator()(T1, T2, T3) exists and if the operator is selected as the best match function by the overload resolution mechanism ([over.match.best]).

13.5.5 Subscripting [over.sub]

operator[] shall be a non-static member function with exactly one parameter. It implements the subscripting syntax

postfix-expression [ expr-or-braced-init-list ]

Thus, a subscripting expression x[y] is interpreted as x.operator[](y) for a class object x of type T if T::operator[](T1) exists and if the operator is selected as the best match function by the overload resolution mechanism ([over.match.best]). [ Example:

struct X {
  Z operator[](std::initializer_list<int>);
};
X x;
x[{1,2,3}] = 7;           // OK: meaning x.operator[]({1,2,3})
int a[10];
a[{1,2,3}] = 7;           // error: built-in subscript operator

 — end example ]

13.5.6 Class member access [over.ref]

operator-> shall be a non-static member function taking no parameters. It implements the class member access syntax that uses ->.

postfix-expression -> templateopt id-expression
postfix-expression -> pseudo-destructor-name

An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator->() exists and if the operator is selected as the best match function by the overload resolution mechanism ([over.match]).

13.5.7 Increment and decrement [over.inc]

The user-defined function called operator++ implements the prefix and postfix ++ operator. If this function is a non-static member function with no parameters, or a non-member function with one parameter, it defines the prefix increment operator ++ for objects of that type. If the function is a non-static member function with one parameter (which shall be of type int) or a non-member function with two parameters (the second of which shall be of type int), it defines the postfix increment operator ++ for objects of that type. When the postfix increment is called as a result of using the ++ operator, the int argument will have value zero.135Example:

struct X {
  X&   operator++();            // prefix ++a
  X    operator++(int);         // postfix a++
};

struct Y { };
Y&   operator++(Y&);            // prefix ++b
Y    operator++(Y&, int);       // postfix b++

void f(X a, Y b) {
  ++a;                          // a.operator++();
  a++;                          // a.operator++(0);
  ++b;                          // operator++(b);
  b++;                          // operator++(b, 0);

  a.operator++();               // explicit call: like ++a;
  a.operator++(0);              // explicit call: like a++;
  operator++(b);                // explicit call: like ++b;
  operator++(b, 0);             // explicit call: like b++;
}

 — end example ]

The prefix and postfix decrement operators -- are handled analogously.

Calling operator++ explicitly, as in expressions like a.operator++(2), has no special properties: The argument to operator++ is 2.

13.5.8 User-defined literals [over.literal]

literal-operator-id:
    operator string-literal identifier
    operator user-defined-string-literal

The string-literal or user-defined-string-literal in a literal-operator-id shall have no encoding-prefix and shall contain no characters other than the implicit terminating '\0'. The ud-suffix of the user-defined-string-literal or the identifier in a literal-operator-id is called a literal suffix identifier. Some literal suffix identifiers are reserved for future standardization; see [usrlit.suffix]. A declaration whose literal-operator-id uses such a literal suffix identifier is ill-formed; no diagnostic required.

A declaration whose declarator-id is a literal-operator-id shall be a declaration of a namespace-scope function or function template (it could be a friend function ([class.friend])), an explicit instantiation or specialization of a function template, or a using-declaration ([namespace.udecl]). A function declared with a literal-operator-id is a literal operator. A function template declared with a literal-operator-id is a literal operator template.

The declaration of a literal operator shall have a parameter-declaration-clause equivalent to one of the following:

const char*
unsigned long long int
long double
char
wchar_t
char16_t
char32_t
const char*, std::size_t
const wchar_t*, std::size_t
const char16_t*, std::size_t
const char32_t*, std::size_t

If a parameter has a default argument ([dcl.fct.default]), the program is ill-formed.

A raw literal operator is a literal operator with a single parameter whose type is const char*.

The declaration of a literal operator template shall have an empty parameter-declaration-clause and its template-parameter-list shall have a single template-parameter that is a non-type template parameter pack ([temp.variadic]) with element type char.

Literal operators and literal operator templates shall not have C language linkage.

Note: Literal operators and literal operator templates are usually invoked implicitly through user-defined literals ([lex.ext]). However, except for the constraints described above, they are ordinary namespace-scope functions and function templates. In particular, they are looked up like ordinary functions and function templates and they follow the same overload resolution rules. Also, they can be declared inline or constexpr, they may have internal or external linkage, they can be called explicitly, their addresses can be taken, etc.  — end note ]

Example:

void operator "" _km(long double);                  // OK
string operator "" _i18n(const char*, std::size_t); // OK
template <char...> double operator "" _\u03C0();    // OK: UCN for lowercase pi
float operator ""_e(const char*);                   // OK
float operator ""E(const char*);                    // error: reserved literal suffix ([usrlit.suffix], [lex.ext])
double operator""_Bq(long double);                  // OK: does not use the reserved identifier _Bq ([lex.name])
double operator"" _Bq(long double);                 // uses the reserved identifier _Bq ([lex.name])
float operator " " B(const char*);                  // error: non-empty string-literal
string operator "" 5X(const char*, std::size_t);    // error: invalid literal suffix identifier
double operator "" _miles(double);                  // error: invalid parameter-declaration-clause
template <char...> int operator "" _j(const char*); // error: invalid parameter-declaration-clause
extern "C" void operator "" _m(long double);        // error: C language linkage

 — end example ]