Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The . (dot) operator is the direct member access operator in C++. It evaluates the left operand to identify a specific object instance and resolves the right operand to access a declared member (data, function, or enumerator) of that object’s type.
postfix_expression . id_expression
postfix_expression . template id_expression
postfix_expression . pseudo_destructor_name

Operand Constraints

  • Left Operand (postfix_expression): Must evaluate to an object of a complete class, struct, or union type. If the expression consists of a reference variable, its type is adjusted to the referenced type prior to analysis, and it evaluates as an lvalue of that non-reference type. Alternatively, if the right operand is a pseudo-destructor call, the left operand must evaluate to a scalar type (which explicitly includes pointer types).
  • Right Operand (id_expression or pseudo_destructor_name): Must be a valid identifier naming a member belonging to the static type of the left operand or its base classes, or a valid pseudo-destructor call for the scalar type of the left operand. If the right operand names a type, the program is ill-formed; nested types must be accessed via the scope resolution operator ::.

The template Disambiguator

When the left operand evaluates to a dependent type within a template definition, and the right operand names a member template, the template keyword must immediately follow the . operator. This syntactic requirement disambiguates the subsequent < character, instructing the compiler to parse it as the start of a template argument list rather than the less-than operator.

Value Category Propagation

The value category of the resulting expression depends strictly on the value category of the left operand and the nature of the member being accessed:
  • Non-static data members: The value category depends on the member’s declared type. If the member is a reference type, the resulting expression is always an lvalue. For non-reference members, the result inherits the value category of the left operand: an lvalue left operand yields an lvalue, while an rvalue (prvalue or xvalue) left operand yields an xvalue.
  • Static data members: The result is always an lvalue, regardless of the left operand’s value category, because static members reside in a single memory location independent of the instance.
  • Non-static member functions: The expression is a prvalue of a special “member function” type. It cannot be evaluated on its own and must immediately be used as the left operand of the function call operator ().
  • Static member functions: The result is always an lvalue designating the static function.
  • Member enumerators: The result is always a prvalue of the enumeration type.

CV-Qualification Inheritance

When accessing a non-static data member, the resulting expression generally inherits the cv-qualifiers (const and volatile) of the left operand.
const ClassType obj;
obj.member; // If 'member' is a non-reference 'MemberType', the result is 'const MemberType'
There are two strict exceptions where cv-qualifiers are not inherited:
  1. Reference Members: If the data member is a reference type, it does not inherit the cv-qualifiers of the left operand. Accessing an int& member on a const ClassType object yields an int&, not a const int&.
  2. Mutable Members: If a non-reference data member is declared with the mutable storage class specifier, it does not inherit the const qualification from the left operand and remains modifiable even if the object is const.

Name Lookup and Resolution

The compiler performs name lookup for the right operand strictly within the scope of the static type of the left operand. If the left operand is statically a base class type, the . operator resolves to the base class member, regardless of the object’s dynamic (runtime) type. Virtual function dispatch is a property of the function call operator (), not the . operator’s name lookup. If the member is overloaded (e.g., a member function), overload resolution occurs based on the arguments provided in the subsequent function call operator.

Overloading Restrictions

The . operator is one of the few operators in C++ that cannot be overloaded. Its semantics are strictly defined by the language standard to guarantee deterministic member access. This contrasts with the indirect member access operator ->, which can be overloaded.
Master C++ with Deep Grasping Methodology!Learn More