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 & token in C++ is a context-dependent symbol that serves five distinct syntactic and semantic roles: the unary address-of operator, the lvalue reference declarator, the binary bitwise AND operator, the member function reference qualifier, and the lambda capture specifier. The compiler resolves its specific behavior during syntactic and semantic analysis based on operand arity, declaration context, and surrounding grammar.

1. Unary Address-of Operator

When used as a prefix unary operator in an expression, & evaluates to the memory address of its operand.
  • Operand Requirement: The operand must be an lvalue (an object or function that occupies an identifiable location in memory). It cannot be applied to a prvalue (temporary) or an xvalue.
  • Type Yield: If the operand is of type T, the expression &operand yields a prvalue pointer of type T*.
  • Overloadability: This operator can be overloaded for user-defined types. The standard library provides std::addressof to bypass overloaded & operators and guarantee the retrieval of the actual memory address.
#include <iostream>

int main() {
    int object = 42;
    int* ptr = &object; // '&' yields the memory address of 'object'
    return 0;
}

2. Lvalue Reference Declarator

When appended to a type specifier in a declaration, & acts as a declarator modifier rather than an expression operator. It creates an lvalue reference, which is a direct alias to an existing object.
  • Binding: An lvalue reference must be initialized upon declaration and binds permanently to its target lvalue. It cannot be re-seated to refer to a different object.
  • Memory Semantics: At the language level, a reference is not guaranteed to occupy its own storage; the compiler often optimizes it out, treating it as an alternative identifier for the bound object.
  • Type Yield: Modifies type T to type T&.
#include <iostream>

int main() {
    int object = 42;
    int& ref = object; // '&' modifies type int to declare 'ref' as an alias for 'object'
    return 0;
}

3. Binary Bitwise AND Operator

When placed between two operands in an expression, & functions as a binary operator that performs a bitwise AND operation.
  • Operand Requirement: Both operands must be of integral or unscoped enumeration types.
  • Mechanics: The operator compares the operands bit by bit. The resulting bit is set to 1 if and only if both corresponding bits in the operands are 1; otherwise, it is set to 0.
  • Type Yield: Yields a prvalue. The type of the result is the common type determined by standard integral promotions and arithmetic conversions applied to the operands.
#include <cstdint>

int main() {
    uint8_t a = 0b11001100;
    uint8_t b = 0b10101010;
    uint8_t c = a & b; // '&' performs bitwise AND. Result: 0b10001000
    return 0;
}

4. Member Function Reference Qualifier

When appended to the signature of a non-static member function, & acts as a reference qualifier.
  • Mechanics: It restricts the invocation of the member function strictly to lvalue instances of the class. If the object is an rvalue, a function qualified with a single & is added to the initial candidate set during overload resolution, but it is subsequently deemed not viable because the implicit object parameter (an lvalue reference) cannot bind to an rvalue argument.
#include <iostream>

class MyClass {
public:
    void execute() & {
        // '&' restricts execution to lvalue instances of MyClass
    }
};

int main() {
    MyClass obj;
    obj.execute(); // Valid: 'obj' is an lvalue
    
    // MyClass().execute(); // Invalid: MyClass() is a prvalue (rvalue); candidate is not viable
    return 0;
}

5. Lambda Capture Specifier

Within the capture list ([]) of a lambda expression, & dictates how automatic variables from the enclosing scope are captured by the closure type.
  • Capture-Default: When used alone as [&], it acts as a capture-default, instructing the compiler to capture all ODR-used automatic variables from the enclosing scope by lvalue reference.
  • Explicit Capture: When prefixed to a specific variable identifier as [&var], it explicitly captures only that variable by lvalue reference.
#include <iostream>

int main() {
    int x = 0;
    int y = 0;

    auto capture_all = [&]() { x++; y++; };      // '&' captures both x and y by reference
    auto capture_one = [&x, y]() { x++; };       // '&' captures only x by reference

    capture_all();
    capture_one();
    
    return 0;
}
Master C++ with Deep Grasping Methodology!Learn More