CodeNebula
C++23coreexpert

size_t Literal Suffix (uz/zu)

C++23 · Completing Modern · Compiler flag: -std=c++23

Explanation

The `uz` or `zu` suffix creates a `std::size_t` literal directly, eliminating the need for casts in size-related expressions.

Real-World Scenario

Write loop bounds matching container `size()` return type without signed/unsigned mismatch warnings.

Quick Snippet

snippet.cpp
for (auto i = 0uz; i < vec.size(); ++i) { /* no warning */ }

Full Example

size_t_literal.cpp
// CodeNebula - C++23 Example: size_t Literal Suffix
// Compile: g++ -std=c++23 -Wall -Wextra -o example size_t_literal.cpp
// Note: Requires GCC 13+ / Clang 15+ / MSVC 19.34+

// C++23 introduces the 'uz' and 'zu' literal suffixes for std::size_t.
// This eliminates signed/unsigned comparison warnings and awkward casts.

#include <iostream>
#include <vector>
#include <type_traits>

int main() {
    std::cout << "=== size_t Literal Suffix (uz/zu) ===" << std::endl;

    // The new literal suffix
    auto a = 42uz;   // std::size_t
    auto b = 100zu;  // std::size_t (zu is also valid)

    std::cout << "42uz  = " << a << " (size_t: "
              << std::is_same_v<decltype(a), std::size_t> << ")" << std::endl;
    std::cout << "100zu = " << b << " (size_t: "
              << std::is_same_v<decltype(b), std::size_t> << ")" << std::endl;

    // Before C++23: signed/unsigned mismatch warnings
    std::cout << "\n=== Avoiding signed/unsigned warnings ===" << std::endl;
    std::vector<int> vec = {10, 20, 30, 40, 50};

    // OLD way (warning: comparing int with size_t)
    // for (int i = 0; i < vec.size(); ++i) { ... }

    // C++23 way: clean, no warnings
    for (auto i = 0uz; i < vec.size(); ++i) {
        std::cout << "  vec[" << i << "] = " << vec[i] << std::endl;
    }

    // Useful in expressions
    std::cout << "\n=== Arithmetic with size_t literals ===" << std::endl;
    auto half = vec.size() / 2uz;
    auto last = vec.size() - 1uz;
    std::cout << "Vector size:   " << vec.size() << std::endl;
    std::cout << "Half index:    " << half << std::endl;
    std::cout << "Last index:    " << last << std::endl;

    // Comparison of literal types
    std::cout << "\n=== Type verification ===" << std::endl;
    auto x = 0uz;
    std::cout << "0uz is size_t:          "
              << std::is_same_v<decltype(x), std::size_t> << std::endl;
    std::cout << "0uz is unsigned:        "
              << std::is_unsigned_v<decltype(x)> << std::endl;

    // Also: 'z' suffix for signed std::ptrdiff_t / std::ssize_t
    auto signed_val = 42z;  // signed counterpart (ptrdiff_t)
    std::cout << "42z  is signed:         "
              << std::is_signed_v<decltype(signed_val)> << std::endl;

    return 0;
}

/*
Expected output:
=== size_t Literal Suffix (uz/zu) ===
42uz  = 42 (size_t: 1)
100zu = 100 (size_t: 1)

=== Avoiding signed/unsigned warnings ===
  vec[0] = 10
  vec[1] = 20
  vec[2] = 30
  vec[3] = 40
  vec[4] = 50

=== Arithmetic with size_t literals ===
Vector size:   5
Half index:    2
Last index:    4

=== Type verification ===
0uz is size_t:          1
0uz is unsigned:        1
42z  is signed:         1
*/
Run command
g++ -std=c++23 -Wall -Wextra -o example size_t_literal.cpp