Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
80bdc47
Add tutorials for type-erasure, reflection and vanishing-this
jbcoe Jul 19, 2026
6dd069a
Simplify code
jbcoe Jul 22, 2026
0cfcda4
Address review comments
jbcoe Jul 23, 2026
2695373
Remove redundant text
jbcoe Jul 23, 2026
45446e3
Remove redundant text
jbcoe Jul 23, 2026
3cd0bcd
Add additional examples for reflection: substitute and extract
jbcoe Jul 24, 2026
e25ff06
Add multiple inheritance example with empty base classes
jbcoe Jul 24, 2026
9b58f6f
Add --reflection flag to scripts/cmake.py
jbcoe Jul 24, 2026
30c553a
Remove needless comment
jbcoe Jul 25, 2026
dbebfc0
Use --reflection flag to set the compiler
jbcoe Jul 25, 2026
8e64059
No need to specify CC or CXX
jbcoe Jul 26, 2026
90e2950
Add UB mention and missing no_unique_address attributes
jbcoe Jul 26, 2026
4cf496e
Add discussion of access_context
jbcoe Jul 26, 2026
666f64f
Improve message for substitute
jbcoe Jul 26, 2026
1f9763f
Add reflect_constant example
jbcoe Jul 26, 2026
7f2e41e
Add comment showing data_member_options fields
jbcoe Jul 26, 2026
9f955b8
Add alias example
jbcoe Jul 26, 2026
ebc02bf
Use ADL
jbcoe Jul 26, 2026
3549321
Add clarifying comments
jbcoe Jul 26, 2026
7bb0c6e
Simplify cmake.yml to make use of --reflection flag
jbcoe Jul 26, 2026
9c3cd23
Remove needless comment
jbcoe Jul 26, 2026
430f350
Improve comment flow
jbcoe Jul 27, 2026
df25de4
Clean up comments
jbcoe Jul 27, 2026
19fbf0e
Remove premature changes to .clang-format
jbcoe Jul 27, 2026
c3ffa1e
Suppress the worst clang-mis-formatting
jbcoe Jul 27, 2026
9a0f907
Use --reflection flag
jbcoe Jul 27, 2026
92c091c
Address review comment - use ranges not raw loops
jbcoe Jul 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,18 @@ jobs:
std: 20,
},
}
- {
name: "Ubuntu GCC-16 (C++26 Reflection)",
os: ubuntu-24.04,
compiler:
{
type: GCC16,
version: 16,
cc: "gcc-16",
cxx: "g++-16",
std: 26,
},
}
steps:
- uses: actions/checkout@v4
- uses: seanmiddleditch/gha-setup-ninja@master
Expand All @@ -231,9 +243,15 @@ jobs:
with:
version: ${{ matrix.settings.compiler.version }}
platform: x64
- name: Install GCC 16 from ubuntu-toolchain-r PPA
if: matrix.settings.compiler.type == 'GCC16'
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install -y --no-install-recommends g++-16 gcc-16
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Set up Python
run: uv sync
- name: Run CMake
run: ./scripts/cmake.sh --${{ matrix.configuration == 'Debug' && 'debug' || 'release' }}
run: ./scripts/cmake.sh --${{ matrix.configuration == 'Debug' && 'debug' || 'release' }} ${{ matrix.settings.compiler.type == 'GCC16' && '--reflection' || '' }}
53 changes: 53 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,34 @@ option(ENABLE_UBSAN "Enable Undefined Behaviour Sanitizer" OFF)
option(ENABLE_TSAN "Enable Thread Sanitizer" OFF)
option(ENABLE_MSAN "Enable Memory Sanitizer" OFF)

option(
XYZ_PROTOCOL_BUILD_REFLECTION_TUTORIAL
"Also build and test tutorials/3_reflection.cc, which requires a compiler \
with C++26 P2996 reflection support (GCC 16+ with -freflection)."
OFF)

if(XYZ_PROTOCOL_BUILD_REFLECTION_TUTORIAL)
include(CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_FLAGS "-std=c++26 -freflection")
check_cxx_source_compiles(
"
#include <meta>
constexpr std::meta::info reflection_of_int = ^^int;
int main() {}
"
XYZ_PROTOCOL_REFLECTION_SUPPORTED)
unset(CMAKE_REQUIRED_FLAGS)
if(NOT XYZ_PROTOCOL_REFLECTION_SUPPORTED)
message(
FATAL_ERROR
"XYZ_PROTOCOL_BUILD_REFLECTION_TUTORIAL is ON but the compiler "
"(${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}) does not "
"accept '-std=c++26 -freflection'. C++26 reflection currently "
"requires GCC 16 or newer; configure with e.g. "
"CXX=g++-16 CC=gcc-16 and a separate build directory (-B).")
endif()
endif()

if(ENABLE_ASAN OR ENABLE_UBSAN OR ENABLE_TSAN OR ENABLE_MSAN)
set(ENABLE_SANITIZERS ON)
endif()
Expand Down Expand Up @@ -148,6 +176,31 @@ if(XYZ_PROTOCOL_IS_NOT_SUBPROJECT)
target_include_directories(protocol_test
PRIVATE ${CMAKE_CURRENT_BINARY_DIR})

# Standalone teaching tutorials (tutorials/) -- see tutorials/README.md.
# Each is self-contained, with no dependency on protocol.h.
xyz_add_test(
NAME
type_erasure_tutorial
FILES
tutorials/1_type_erasure.cc)

xyz_add_test(
NAME
vanishing_this_pointer_tutorial
FILES
tutorials/2_vanishing_this_pointer.cc)

if(XYZ_PROTOCOL_BUILD_REFLECTION_TUTORIAL)
xyz_add_test(
NAME
reflection_tutorial
VERSION
26
FILES
tutorials/3_reflection.cc)
target_compile_options(reflection_tutorial PRIVATE -freflection)
endif()

add_executable(protocol_benchmark protocol_benchmark.cc)
target_link_libraries(protocol_benchmark PRIVATE protocol benchmark::benchmark)
add_dependencies(protocol_benchmark generate_protocols)
Expand Down
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,20 @@ This library is an active proof of concept and is subject to change.
- Development: Use this library for understanding its concepts and
contributing to its development. Avoid using it in production code.

## Interactive Docker Shell

To launch an interactive bash shell in the pre-configured Docker container (which includes GCC 16, Python, CMake, and `uv`) without running an AI agent, use:

```bash
./scripts/docker-shell.sh [--rebuild-docker]
```

Inside the shell, GCC 16 is what lets you build and run the `tutorials/3_reflection.cc` tutorial, which needs C++26 reflection support:

```bash
./scripts/cmake.sh --release --reflection -B build-reflection
```

## AI Coding Sandboxes

The repository includes a Docker-based sandbox script for AI coding
Expand Down
3 changes: 2 additions & 1 deletion GEMINI.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ general defaults for this repository.
- **Tooling:** Always use `uv` for Python dependency management (`uv run ...`).
- **Build & Test:** Use `scripts/cmake.sh` for all build and test operations.
The `scripts/cmake.sh` entrypoint supports `--debug`, `--release`,
`--asan`, `--ubsan`, `--tsan`, and `--msan`.
`--asan`, `--ubsan`, `--tsan`, `--msan`, and `--reflection` (builds and
tests `tutorials/3_reflection.cc`, requires a P2996 reflection compiler).
- **Compiler Preferences:** Prefer Clang 19+ for sanitizer-based verification
and CI, as it provides superior support for MSAN and TSAN compared to
older GCC versions.
Expand Down
2 changes: 1 addition & 1 deletion cmake/xyz_add_test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function(xyz_add_test)
if(NOT XYZ_VERSION)
set(XYZ_VERSION 20)
else()
set(VALID_TARGET_VERSIONS 11 14 17 20 23)
set(VALID_TARGET_VERSIONS 11 14 17 20 23 26)
list(FIND VALID_TARGET_VERSIONS ${XYZ_VERSION} index)
if(index EQUAL -1)
message(FATAL_ERROR "TYPE must be one of <${VALID_TARGET_VERSIONS}>")
Expand Down
7 changes: 7 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/nul
&& apt-get update && apt-get install -y --no-install-recommends cmake \
&& rm -rf /var/lib/apt/lists/*

# Install GCC 16 (experimental C++26 reflection support via -std=c++26
# -freflection, see https://gcc.gnu.org/gcc-16/changes.html) from the Ubuntu
# Toolchain Test PPA, since Ubuntu 24.04's own repos only go up to GCC 14.
RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test \
&& apt-get update && apt-get install -y --no-install-recommends g++-16 gcc-16 \
&& rm -rf /var/lib/apt/lists/*

# Install bazelisk.
RUN ARCH=$(dpkg --print-architecture) && \
wget https://github.com/bazelbuild/bazelisk/releases/download/v1.25.0/bazelisk-linux-${ARCH} -O /usr/local/bin/bazelisk \
Expand Down
20 changes: 19 additions & 1 deletion scripts/cmake.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""CMake helper script for building and testing the project."""

import argparse
import os
import subprocess
from typing import Any

Expand Down Expand Up @@ -37,6 +38,12 @@ def main() -> None:
)
parser.add_argument("--tsan", action="store_true", help="Enable Thread Sanitizer")
parser.add_argument("--msan", action="store_true", help="Enable Memory Sanitizer")
parser.add_argument(
"--reflection",
action="store_true",
help="Build and test tutorials/3_reflection.cc (requires a P2996 "
"reflection compiler, e.g. CXX=g++-16 CC=gcc-16)",
)
parser.add_argument("-B", "--build-dir", help="Build directory")
parser.add_argument(
"--clean", action="store_true", help="Fresh configuration and clean-first build"
Expand Down Expand Up @@ -74,6 +81,8 @@ def log(msg: Any) -> None:
f"-DENABLE_UBSAN={'ON' if args.ubsan else 'OFF'}",
f"-DENABLE_TSAN={'ON' if args.tsan else 'OFF'}",
f"-DENABLE_MSAN={'ON' if args.msan else 'OFF'}",
"-DXYZ_PROTOCOL_BUILD_REFLECTION_TUTORIAL="
+ ("ON" if args.reflection else "OFF"),
]
if args.build_dir:
configure_args.extend(["-B", args.build_dir])
Expand All @@ -82,8 +91,17 @@ def log(msg: Any) -> None:

configure_args.extend(extra)

# A P2996 reflection compiler is required to configure with
# XYZ_PROTOCOL_BUILD_REFLECTION_TUTORIAL=ON. CMake only reads CXX/CC
# from the environment, not from -D cache variables, so set them here
# rather than as configure_args.
configure_env = os.environ.copy()
if args.reflection:
configure_env["CXX"] = "g++-16"
configure_env["CC"] = "gcc-16"

log(f"Running: {' '.join(configure_args)}")
subprocess.check_call(configure_args)
subprocess.check_call(configure_args, env=configure_env)

# Build step (required for build, test, benchmark)
build_args = ["cmake", "--build"]
Expand Down
29 changes: 29 additions & 0 deletions scripts/docker-shell.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash
set -eu -o pipefail

WORKSPACE_ROOT=$(git rev-parse --show-toplevel)
IMAGE_NAME="cc-protocol-sandbox"

REBUILD=0
for argument in "$@"; do
if [ "$argument" == "--rebuild-docker" ]; then
REBUILD=1
fi
done

if [ "$REBUILD" -eq 1 ] || ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1; then
echo "--- Building Docker Image: ${IMAGE_NAME} ---"
docker build -t "$IMAGE_NAME" -f "${WORKSPACE_ROOT}/docker/Dockerfile" "$WORKSPACE_ROOT"
fi

echo "--- Starting Interactive Docker Shell ---"
echo "Project root ${WORKSPACE_ROOT} is mounted at /workspace"
echo ""
echo "To build and test with the C++26 reflection backend (GCC 16):"
echo " ./scripts/cmake.sh --release --reflection -B build-reflection"
echo ""

exec docker run -it --rm \
-v "${WORKSPACE_ROOT}:/workspace" \
-w /workspace \
"$IMAGE_NAME" bash
Loading
Loading