Accesses a member of its operand.
Operator name | Syntax | Overloadable | Prototype examples (for class T ) |
|
---|---|---|---|---|
Inside class definition | Outside class definition | |||
subscript | a[b] | Yes | R& T::operator[](S b); | N/A |
indirection | *a | Yes | R& T::operator*(); | R& operator*(T a); |
address-of | &a | Yes | R* T::operator&(); | R* operator&(T a); |
member of object | a.b | No | N/A | N/A |
member of pointer | a->b | Yes | R* T::operator->(); | N/A |
pointer to member of object | a.*b | No | N/A | N/A |
pointer to member of pointer | a->*b | Yes | R& T::operator->*(S b); | R& operator->*(T a, S b); |
Notes
|
Built-in subscript operator provides access to an object of function pointed-to by the pointer or array operand.
Built-in indirection operator provides access to an object or function pointed-to by the pointer operand.
Built-in address-of operator creates a pointer pointing to the object or function operand.
Member of object and pointer to member of object operators provide access to a data member or member function of the class operand.
Built-in member of pointer and pointer to member of pointer operators provide access to a data member or member function of the class pointed-to by the pointer operand.
For every object type T
(possibly cv-qualified), the following function signature participates in overload resolution:
T& operator[](T*, std::ptrdiff_t); | ||
T& operator[](std::ptrdiff_t, T*); |
The non-pointer operand may be any expression of integral or unscoped enumeration type, it is implicitly converted to std::ptrdiff_t
. The expression E1[E2]
is exactly identical to the expression *(E1 + E2)
, that is, the pointer operand (which may be a result of array-to-pointer conversion, and which must point to an element of some array or one past the end) is adjusted to point to another element of the same array, following the rules of pointer arithmetics, and is then dereferenced.
When applied to an array, the subscript expression is an lvalue if the array is an lvalue, and an xvalue if it isn't (since C++11). When applied to a pointer, the subscript expression is always an lvalue.
The type T
is not allowed to be an incomplete type, even if the size or internal structure of T
is never used, as in &x[0]
.
#include <iostream> int main() { int a[4] = {1, 2, 3, 4}; int* p = &a[2]; std::cout << p[1] << p[-1] << 1[p] << (-1)[p] << '\n'; }
Output:
4242
For every type T
that is either object type (possibly cv-qualified) or function type (not const- or ref-qualified), the following function signature participates in overload resolution:
T& operator*(T*); |
The operand of the built-in indirection operator is a pointer to object or function, and the result is the lvalue that the pointer is pointing to. Note that a pointer to incomplete type can be dereferenced, e.g. when initializing a reference.
#include <iostream> int f() { return 42; } int main() { int n = 1; int* pn = &n; int& r = *pn; // lvalue can be bound to a reference int m = *pn; // indirection + lvalue-to-rvalue conversion int (*fp)() = &f; int (&fr)() = *fp; // function lvalue can be bound to a reference }
The operand of the built-in operator&
is either an lvalue expression of any type or the qualified name of a non-static data member or member function in some class. This operator does not participate in overload resolution. If there are no viable functions, special rules are used:
T
, operator&
creates and returns a prvalue of type T*
, with the same cv qualification, that is pointing to the object designated by the operand. If the operand has incomplete type, the pointer can be formed, but if that incomplete type happens to be a class that defines its own operator&
, the behavior is undefined (until C++14) it is unspecified whether the built-in or the overload is used (since C++14). For the operands of type with user-defined operator&
, std::addressof
may be used to obtain the true pointer. &C::member
, the result is a prvalue pointer to member function or pointer to data member of type T
in class C
. Note that neither &member
nor C::member
nor even &(C::member)
may be used to initialize a pointer to member. void f(int) {} void f(double) {} struct A { int i; }; struct B { void f(); }; int main() { int n = 1; int* pn = &n; // pointer int* pn2 = &*pn; // pn2 == pn int A::* mp = &A::i; // pointer to data member void (B::*mpf)() = &B::f; // pointer to member function void (*pf)(int) = &f; // overload resolution due to initialization context // auto pf2 = &f; // error: ambiguous overloaded function type auto pf2 = static_cast<void (*)(int)>(&f); // overload resolution due to cast }
The first operand of the operator.
is an expression of complete class type T
. The first operand of the built-in operator->
is an expression of pointer to complete class type T*
. The first operand of both operators is evaluated even if it is not necessary (e.g. when the second operand names a static member).
The second operand of both operators is a name of (formally, an id-expression that names) a data member or member function of T
or of an unambiguous and accessible base class B
of T
(e.g. E1.E2
or E1->E2
), optionally qualified (e.g. E1.B::E2
or E1->B::E2
), optionally using template disambiguator (e.g. E1.template E2
or E1->template E2
).
If a user-defined operator->
is provided, the operator->
is called again on the value that it returns, recursively, until an operator->
is reached that returns a plain pointer. After that, built-in semantics are applied to that pointer.
The expression E1->E2
is exactly equivalent to (*E1).E2
for built-in types; that is why the following rules address only E1.E2
.
In the expression E1.E2
:
E2
is a static data member: E2
is of reference type T&
or T&&
, the result is an lvalue of type T
designating the object or function to which E2
refers, E1
is evaluated and discarded in both cases; 2) if E2
is a non-static data member: E2
is of reference type T&
or T&&
, the result is an lvalue of type T
designating the object or function to which E2
refers, E1
is an lvalue, the result is an lvalue designating that non-static data member of E1
, E1
is an rvalue (until C++17)xvalue (which may be materialized from prvalue) (since C++17)), the result is an rvalue (until C++11)xvalue (since C++11) designating that non-static data member of E1
. E2
is not a mutable member, the cv-qualification of the result is the union of the cv-qualifications of E1
and E2
, otherwise (if E2
is a mutable member), it is the union of the volatile-qualifications of E1
and E2
; E2
is a static member function, the result is an lvalue designating that static member function. Essentially, E1
is evaluated and discarded in this case;E2
is a non-static member function including a destructor, the result is a special kind of prvalue designating that non-static member function of E1
that can only be used as the left-hand operand of a member function call operator, and for no other purpose;E2
is a member enumerator, the result is a prvalue equal to that member enumerator of E1
;E1
is a scalar type and E2
is a ~
followed by the type name or decltype specifier designating the same type (minus cv-qualifications), optionally qualified, the result is a special kind of prvalue that can only be used as the left-hand operand of a function call operator, and for no other purpose. The resulting function call expression is called pseudo destructor call. It takes no arguments, returns void, and performs no action other than initial evaluation of E1
. This is the only case where the left-hand operand of operator.
has non-class type. Allowing pseudo destructor call makes it possible to write code without having to know if a destructor exists for a given type.#include <iostream> struct P { template<typename T> static T* ptr() { return new T; } }; template<typename T> struct A { A(int n): n(n) {} int n; static int sn; int f() { return 10 + n; } static int sf() { return 4; } class B {}; enum E {RED = 1, BLUE = 2}; void g() { typedef int U; // keyword template needed for a dependent template member int* p = T().template ptr<U>(); p->~U(); // U is int, calls int's pseudo destructor delete p; } }; template<> int A<P>::sn = 2; int main() { A<P> a(1); std::cout << a.n << ' ' << a.sn << ' ' // A::sn also works << a.f() << ' ' << a.sf() << ' ' // A::sf() also works // << a.B << ' ' // error: nested type not allowed << a.RED << ' '; // enumerator }
Output:
1 2 11 4 1
The first operand of the operator.*
is an expression of class type T
. The first operand of the operator->*
is an expression of type pointer to class type T*
.
The second operand of both operators is an expression of type pointer to member of T
or pointer to member of an unambiguous and accessible base class B
of T
.
For every combination of types D
, B
, R
, where class type B
is either the same class as D
or an unambiguous and accessible base class of D
, and R
is either an object or function type, the following function signature participates in overload resolution:
R& operator->*(D*, R B::*); |
where both operands may be cv-qualified, in which case the return type's cv-qualification is the union of the cv-qualification of the operands.
The expression E1->*E2
is exactly equivalent to (*E1).*E2
for built-in types; that is why the following rules address only E1.*E2
.
In the expression E1.*E2
:
E2
is a pointer to data member, E1
is an lvalue, the result is an lvalue designating that data member, E1
is an rvalue (until C++17)xvalue (which may be materializedfrom prvalue) (since C++17)), the result is an rvalue (until C++11)xvalue (since C++11) designating that data member;E2
is a pointer to member function, the result is a special kind of prvalue designating that member function that can only be used as the left-hand operand of a member function call operator, and for no other purpose;E2
is a null pointer-to-member value, the behavior is undefined;E1
does not contain the member to which E2
refers, the behavior is undefined;E1
is an rvalue and E2
points to a member function with ref-qualifier &, the program is ill-formed;E1
is an lvalue and E2
points to a member function with ref-qualifier &&, the program is ill-formed.#include <iostream> struct S { S(int n): mi(n) {} mutable int mi; int f(int n) { return mi + n; } }; struct D: public S { D(int n): S(n) {} }; int main() { int S::* pmi = &S::mi; int (S::* pf)(int) = &S::f; const S s(7); // s.*pmi = 10; // error: cannot modify through mutable std::cout << s.*pmi << '\n'; D d(7); // base pointers work with derived object D* pd = &d; std::cout << (d.*pf)(7) << ' ' << (pd->*pf)(8) << '\n'; }
Output:
7 14 15
Subscript operator is overloaded by many standard container classes.
accesses specific bit (public member function of std::bitset ) |
|
provides indexed access to the managed array (public member function of std::unique_ptr ) |
|
access specified character (public member function of std::basic_string ) |
|
access specified element (public member function of std::array ) |
|
access specified element (public member function of std::deque ) |
|
access specified element (public member function of std::vector ) |
|
access specified element (public member function of std::map ) |
|
access specified element (public member function of std::unordered_map ) |
|
accesses an element by index (public member function of std::reverse_iterator ) |
|
accesses an element by index (public member function of std::move_iterator ) |
|
get/set valarray element, slice, or mask (public member function of std::valarray ) |
|
returns specified sub-match (public member function of std::match_results ) |
The indirection and member operators are overloaded by many iterators and smart pointer classes.
dereferences pointer to the managed object (public member function of std::unique_ptr ) |
|
dereferences the stored pointer (public member function of std::shared_ptr ) |
|
accesses the managed object (public member function of std::auto_ptr ) |
|
dereferences the iterator (public member function of std::raw_storage_iterator ) |
|
dereferences the decremented underlying iterator (public member function of std::reverse_iterator ) |
|
no-op (public member function of std::back_insert_iterator ) |
|
no-op (public member function of std::front_insert_iterator ) |
|
no-op (public member function of std::insert_iterator ) |
|
accesses the pointed-to element (public member function of std::move_iterator ) |
|
returns the current element (public member function of std::istream_iterator ) |
|
no-op (public member function of std::ostream_iterator ) |
|
(since C++11)
| obtains a copy of the current character accesses a member of the current character, if CharT has members (public member function of std::istreambuf_iterator ) |
no-op (public member function of std::ostreambuf_iterator ) |
|
accesses the current match (public member function of std::regex_iterator ) |
|
accesses current submatch (public member function of std::regex_token_iterator ) |
No standard library classes overload operator&
. The best known example of overloaded operator&
is the Microsoft COM class CComPtr, although it can also appear in EDSLs such as boost.spirit.
No standard library classes overload operator->*
. It was suggested that it could be part of smart pointer interface, and in fact is used in that capacity by actors in boost.phoenix, but is more common in EDSLs such as cpp.react.
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 1213 | C++11 | subscripting an array rvalue resulted in lvalue | reclassified as xvalue |
Common operators | ||||||
---|---|---|---|---|---|---|
assignment | increment decrement | arithmetic | logical | comparison | member access | other |
|
|
|
|
|
|
|
Special operators | ||||||
|
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
http://en.cppreference.com/w/cpp/language/operator_member_access