Code is written by models now. C+ is legible enough that a person can audit every line, and strict enough that a model has few ways to get it wrong.
A compiled, statically typed systems language: native machine code through LLVM, no VM, no garbage collector, manual memory made safe by a borrow checker, two-way C interop.
Runs on macOS, Linux, Windows · cross-compiles to iOS, Android, ESP32 · LSP for VS Code & Neovim
$ cpc hello.cplus -o hello $ ./hello hello, world
Native apps on macOS (AppKit), iOS (UIKit), Linux (GTK 4 / libadwaita), and Windows (Win32).
Natively compiled services with no GC and predictable memory.
Fast, memory-safe CLI tools, compiled to a single static binary by the cpc compiler.
Native speed, no runtime tax.
C+ compiles directly to native code through LLVM. The borrow checker and restrict markers give the optimizer the aliasing guarantees it needs to vectorize hot loops. No annotations to remember, just the ones the type system already proved.
// noalias hot loop, vectorizes cleanly fn axpy(n: usize, a: f32, restrict x: *f32, restrict y: *f32) { var i: usize = 0 as usize; while i < n { y[i] = a * x[i] + y[i]; i = i +% 1; } return; }
Concise code, few ways to go wrong.
Structs, methods, generics, and pattern matching, with no overloading, no implicit conversions, and no closures to reason about. Fewer ways to write it wrong, and exact, numbered diagnostics when you do.
struct Point { x: i32, y: i32 } impl Point { fn translate(ref this, dx: i32, dy: i32) { this.x = this.x +% dx; this.y = this.y +% dy; return; } }
Why "safer," not "safe."
C+ is not a sandbox, and does not pretend to be. Raw pointers, foreign calls, and other operations that can cause undefined behaviour stay your responsibility. The difference from C is that each one is visible in the source itself (a raw-pointer dereference, a pointer cast, an extern call), so nothing dangerous hides from a reviewer. What the language does remove outright: no null, no exceptions, no uninitialized reads, and a borrow checker that enforces aliasing-xor-mutation so data races don't compile, with Drop / defer for deterministic cleanup. That is the whole claim, and the reason the word is "safer," not "safe": far fewer ways to crash by accident, and the operations that still can are the ones you can see.
struct Buf { ptr: *u8, len: usize } impl Buf { // runs automatically on scope exit fn drop(ref this) { free(this.ptr); } } fn main() -> i32 { let b: Buf = make_buf(); defer #println("cleaning up"); return 0; }
Audio callbacks, control loops, and frame hot paths can't afford a hidden allocation or a lock. Mark a function #[realtime] and the compiler proves it across the entire transitive call graph: no heap allocation, no blocking, no unbounded recursion, no unknown calls. Not a lint. A compile error.
#[no_alloc] · rejects any path to malloc#[no_block] · rejects locks, waits, and blocking I/O#[max_stack(N)] · bounded, ABI-accurate frame sizevendor/rt#[realtime] PID run on an ESP32
// compiler-checked: a violation won't compile #[realtime] fn process_frame(input: f32x4[], output: f32x4[]) { let n: usize = output.len(); var i: usize = 0 as usize; while i < n { output[i] = input[i] * GAIN; // pure SIMD math i = i +% 1; } // Vec::new / lock / sleep here → E0901 / E0907 return; }
C+ calls C, Objective-C, and Metal directly through extern fn, with no binding layer and no glue generator. And because cpc emits standard C-ABI object files, existing C and C++ projects link C+ straight back: drop a .o into a CMake build and replace functions one symbol at a time, until the binary stands on its own. And when wrapping a whole system framework by hand would mean pages of declarations, cpc-bindgen generates the C+ package for you, reading Objective-C and Swift interfaces and bridging objects, collections, delegates, and blocks both ways.
// ① C+ calls C, no bindings extern fn cblas_sdot(n: i32, x: *f32, ix: i32, y: *f32, iy: i32) -> f32;
// ② C links C+ back, a plain C symbol #[repr(C)] export extern fn cplus_dot(restrict a: *f32, restrict b: *f32, n: usize) -> f32 { // ... emits `cplus_dot` for clang / CMake to link return 0.0f32; }
No GC, no runtime overhead. A single-threaded raytracer, release build, on Apple Silicon.
Ray Tracing in One Weekend · 800×450 · 32 spp · release build, Apple Silicon.
Install the cpc toolchain and build your first program in seconds.
# macOS (Apple Silicon) $ brew install netdur/cplus/cplus $ cpc --version
Prebuilt binaries, no toolchain to build. Supported toolchains: macOS M-series, Linux x86-64 (.deb), and Windows x86-64 (.zip); from any of them cpc cross-compiles to iOS, Android, and ESP32. Linux and Windows builds are on the GitHub releases page.
Every feature C+ leaves out removes a class of mistake: no closures means no capture semantics to get wrong, no overloading means one name resolves to one signature, no implicit conversions means every width change is visible in the source. Ownership is on every parameter, every crash-capable operation is visible in the source, and imports name their source.
What looks verbose is deliberate. The explicit return, the visible as cast, the spelled-out 0 as usize: explicitness over elegance, by design, so the same code reads the same way to a person and to a model. There is no clever shorthand to learn and no hidden control flow to infer.
When something is wrong, the compiler is exact about it: diagnostics are numbered, spanned, and machine-readable, and cpc check --diagnostics=json makes them trivial to act on. The compiler is part of writing the code, not just the gate at the end.
$ cpc check --diagnostics=json // one JSON object per diagnostic, ready to repair { "code": "E0305", "level": "error", "span": { "file": "main.cplus", "line": 4, "col": 5 }, "message": "cannot assign to immutable binding `total`; declare it as `var`" }
If the model writes most of the lines, the tooling should speak to the model. cpc exposes the compiler's own resolved, typed view of your code as a queryable graph, so an agent navigates by symbol and type instead of grepping text.
cpc query · def / refs / callers / callees / type-at / value-refs, plus a one-call context edit-pack — all JSON with file:line:colcpc mcp · a resident MCP server over that graph, for an agent loop.md), with an llms.txt mapagent_core / agent_mcp / agent_appkit · expose a running app for an agent to drive over MCP$ cpc query context sum_range // one call: signature, callers, callees, types { "target": { "signature": "fn sum_range(r: Range) -> i64" }, "callers": [ "src.main::run" ], "callees": [ "src.geo::Range::len" ], "unresolved": 0 } $ cpc mcp // resident MCP server over the graph // tools: find_definition, find_references, // find_callers, code_context, type_at
Built in the open. Contribute and get involved.