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 typeid operator is a C++ language facility that queries type information at compile-time or runtime. It yields an lvalue of static type const std::type_info representing the exact type of the operand.

Syntax

typeid(type-id)
typeid(expression)
To use the typeid operator, the <typeinfo> standard library header must be included.

Completeness Requirement

When typeid is applied to a type-id representing a class type, or to an expression whose static type is a class type, that class type must be completely defined. Applying typeid to an incomplete type results in a compilation error.

Evaluation Mechanics

The evaluation strategy of typeid strictly depends on the value category and polymorphism of its operand: 1. Runtime Evaluation (Dynamic Type / RTTI) Runtime evaluation only occurs if the operand is a glvalue expression of a polymorphic class type (a class declaring or inheriting at least one virtual function). The operator inspects the virtual table (vtable) of the object to determine its most derived dynamic type. Because it requires runtime resolution, the expression itself is evaluated. 2. Compile-Time Evaluation (Static Type) For all other operands, typeid is resolved entirely at compile-time based on the static type. This includes:
  • Any type-id.
  • Expressions of non-polymorphic types.
  • prvalue expressions of polymorphic types (e.g., typeid(Base())).
In these compile-time scenarios, the expression is treated as an unevaluated operand; no runtime execution of the expression occurs.

Type Adjustments

Before the std::type_info object is generated, the C++ compiler applies specific type adjustments:
  • Reference Stripping: If the operand is a type-id representing a reference type (T& or T&&), typeid evaluates the referenced type (T). For expression operands, this rule is implicitly satisfied because C++ expressions do not possess reference types; references are dropped during standard expression evaluation before typeid is applied.
  • CV-Qualifier Stripping: Top-level const and volatile qualifiers are ignored. typeid(const T) and typeid(T) yield std::type_info objects that represent the same type and compare equal via operator==. Pointers to const types (const T*), however, retain their constness because the qualifier is not top-level.

Exception Handling

When evaluating a polymorphic glvalue expression at runtime, if the operand is a dereferenced null pointer (e.g., *ptr where ptr evaluates to a null pointer value), the typeid operator throws an exception of type std::bad_typeid. Dereferencing a null pointer in a compile-time evaluated context (such as a non-polymorphic type or a prvalue) does not throw, because the expression is an unevaluated operand.

Syntax Visualization

#include <typeinfo>
#include <cassert>

struct Base { virtual ~Base() = default; }; // Polymorphic, completely defined
struct Derived : Base {};
struct NonPolyBase {};                      // Non-polymorphic, completely defined

struct Incomplete; // Incomplete type

Base make_base(); // Function returning a prvalue

int main() {
    // ERROR: typeid(Incomplete) would fail to compile because the type is incomplete.

    // 1. Compile-time evaluation: prvalue of a polymorphic type
    // make_base() is an unevaluated operand. No function call occurs at runtime.
    const std::type_info& t1 = typeid(make_base()); 

    // 2. Runtime evaluation: glvalue of a polymorphic type
    Derived d;
    Base& b_ref = d;
    // Evaluates at runtime to the dynamic type (Derived) via the vtable
    const std::type_info& t2 = typeid(b_ref); 

    // 3. Compile-time evaluation: glvalue of a non-polymorphic type
    NonPolyBase npb;
    NonPolyBase& npb_ref = npb;
    // Evaluates at compile-time to the static type (NonPolyBase)
    const std::type_info& t3 = typeid(npb_ref); 

    // 4. Type-ids, reference stripping, and CV-qualifier stripping
    assert(typeid(const int) == typeid(int));
    assert(typeid(int&) == typeid(int)); 

    // 5. Exception on null polymorphic glvalue dereference
    Base* null_ptr = nullptr;
    try {
        const std::type_info& t4 = typeid(*null_ptr); // Throws std::bad_typeid
    } catch (const std::bad_typeid& e) {
        // Exception caught
    }

    // 6. Unevaluated operand (Non-polymorphic null pointer)
    NonPolyBase* np_null = nullptr;
    const std::type_info& t5 = typeid(*np_null); 
    // Safe: Evaluates to NonPolyBase at compile-time. No exception thrown.

    return 0;
}
Master C++ with Deep Grasping Methodology!Learn More