I've been a C programmer for most of my career. The kind who can feel what the CPU is doing. Move a register here, touch a block of memory there, shave off a microsecond. When you think at that level for long enough, you start to resent anything that calls itself "modern."
Not because you can't learn it. Because it feels wrong. Too many layers between you and the metal.
C with classes
For years, my C++ was really just C with classes. I found out later that most people who put "C++ engineer" on their resume are doing exactly the same thing. That's where you plateau, and it's a comfortable plateau. You ship code. It works. Nobody complains.
And a lot of people never leave that plateau. I'm not talking about junior developers. I'm talking about engineers with decades of C experience who never made the jump. The mental model of C is: I own every byte, I control every allocation, I decide when memory lives and dies. Accepting that a destructor will clean up for you, that you should stop calling delete, that std::unique_ptr knows better than you do when to free memory... that goes against everything a C programmer was trained to believe. Plenty of good engineers looked at that and said no thanks.
I almost did too. But then std::vector clicked. Then RAII clicked. Then I ran into compare_exchange_strong and compare_exchange_weak and spent a full day understanding when to use which one. Then C++17 arrived with SFINAE and template metaprogramming.
I questioned my life choices.
50,000 lines by hand
But I kept going, because the payoff was real.
My first serious Modern C++ project was a bridge layer between a trading platform and a strategy execution service. About 50,000 lines, took six months to write by hand. I picked C++ for speed and RAII, and the results justified the pain: on Windows 10, the process started at 22MB of memory, dropped to 11MB after running for a week. On Windows 11, 36MB at start, 12MB after a week. It was pulling tick data for every instrument at full frequency, the entire time.
That was the stage where I could use Modern C++. Vectors, smart pointers, move semantics, atomics. I'd crossed the first two hurdles: from C to C-with-classes, and from C-with-classes to C++11/14. Both were hard. Both filtered out a lot of people.
But those were hurdles you could clear on your own. Give a determined programmer enough time, and RAII will click. Move semantics will click. Smart pointers will click.
The third hurdle is different.
The pipe organ
A pipe organ is the most complex instrument ever built. Thousands of pipes. Four or five keyboards stacked on top of each other, called manuals. A pedalboard at your feet for the bass lines. Dozens of stops that change the sound of every pipe. To play it, you need both hands working different keyboards, both feet on the pedals, and somehow you also need to pull stops in the middle of a piece.
That's four hands' worth of work. You have two.
Modern C++ past C++17 is a pipe organ.
The vertical span alone is disorienting. At the bottom, you're still dealing with cache lines, branch prediction, and what the CPU is actually doing with your alignas(std::hardware_destructive_interference_size). At the top, you're writing concepts and consteval functions that execute entirely during compilation. You need to hold both levels in your head at the same time, because a one-line change at the top can restructure what happens at the bottom.
Then there's the depth. Every line of C++23 is a reverse derivation. std::expected<Value, Error> looks like one line. Behind it is a chain of compiler decisions about storage layout, copy elision, destructor sequencing, and exception-free error propagation that traces all the way back to what would have been fifty lines of C with manual error codes and goto cleanup blocks.
And the sheer width of the thing. Templates. Concepts. Coroutines. Ranges. Modules. PMR. SIMD intrinsics versus portable abstractions. constexpr versus consteval versus constinit. Even the experts specialize. A template metaprogramming wizard might not know the first thing about coroutine frame allocation. A SIMD specialist might never touch ranges.
The Swiss watch inside
Here's the thing people miss when they complain about C++ being too complex: this isn't a design failure. This is a price.
A mechanical watch movement has hundreds of components, machined to micron tolerances. It's absurdly complex. But it's complex because it chose to tell time without a battery, without a circuit board, without any external dependency. That constraint, total self-reliance with precision, is what forces the complexity. A quartz watch does the same job with a battery and a chip. Cheaper, more accurate, simpler. But the mechanical watch gives you something the quartz watch can't: it runs on nothing but itself.
Modern C++ made the same bargain. Zero-cost abstractions. Full hardware control. Compile-time safety. No garbage collector, no runtime, no VM. The language chose to give you everything, from register-level performance to type-level metaprogramming, in one system. That commitment to not compromise on any axis is what makes it so powerful. And it's exactly what makes it so hard to hold in one head.
The organ doesn't have five keyboards because the builder was a sadist. It has five keyboards because the music demands that range.
1,000 lines to 10
You want to see what that bargain looks like in practice? Look at the FIX protocol engine space.
, a high-performance FIX protocol engine in C++23, I didn't just throw code at AI and hope for the best. I wrote a rulebook. Not vaguely. Specifically.
Mandatory patterns: C++23 standard compliance, zero-copy data flow with std::span and move semantics, compile-time optimization with consteval and constexpr, memory sovereignty through PMR pools and cache-line alignment, type safety with strong types and [[nodiscard]], deterministic execution with noexcept and no exceptions on hot paths.
Prohibited patterns: no new/delete on hot paths, no virtual functions in performance-critical code, no std::shared_ptr on hot paths, no floating-point for prices, no dynamic memory allocation during message parsing.
Forty-five numbered techniques, each mapped to specific source files. A six-phase optimization roadmap with measurable success criteria: zero hot-path allocations, cache miss rates below 5%, branch miss rates below 1%. A benchmark framework specifying exactly how to measure, down to RDTSC timing with lfence barriers and cache-line contention tests.
When AI has this kind of context, it doesn't guess about std::expected versus exceptions. The rulebook says no exceptions on hot paths, use std::expected, target deterministic control flow. The decision is already made. AI implements it correctly, in the specific codebase, following the established patterns.
The problem was never that AI couldn't write good C++23. The problem was that without constraints, it had to guess at hundreds of decisions that each require deep domain knowledge. Give it the constraints, and it stops guessing.
Remember those QuickFIX-era 1,000-line object pools? My rulebook has one line about them: "Use std::pmr::monotonic_buffer_resource for hot path allocation." AI reads that, implements the pool with pre-allocation and per-message reset, following the established memory patterns. Hot-path allocations dropped from 12 per message to zero. The 1,000 lines of knowledge that QuickFIX engineers accumulated over years is now compressed into one rule that AI can execute in an afternoon.
SIMD selection: I described the workload, AI prototyped implementations with raw intrinsics, Highway, and xsimd, all following the project's zero-copy and cache-alignment rules. xsimd won. The delimiter scan went from ~150ns to under 12ns. Thirteen times faster.
Compile-time lookup tables: the rulebook includes consteval protocol hardening. AI generated tag lookup tables from the FIX specification, replacing those 300 runtime switch branches the old way required, with compile-time verification that every entry was correct. Improvement ranged from 55% to 97%.
Each of these was a stop on the organ. With proper instructions, AI pulled them correctly.
What actually changed
When C++ reached C++17 and kept going, the language outgrew what one person could handle. The organ got more keyboards, more stops, more pipes. The music it could produce was extraordinary. But the number of hands you'd need to play it kept growing.
AI is the tool that lets us take Modern C++ back.
Not by making it simpler. C++23 is more complex than C++17, which was more complex than C++11. More features, more interactions between features, more ways to get subtly wrong results that compile without complaint.
What collapsed is the time between knowing and doing. "I know std::expected exists" to "I have a benchmarked, integrated implementation" used to take days. Now it takes hours. "I've heard of PMR" to "my hot path has zero allocations" used to take a week. Now it takes a day. The gap between reading about a C++23 feature and actually deploying it in production code has always been the widest in C++. Years wide, sometimes. Careers wide.
AI didn't close that gap. It made it crossable.
You still need to know what you're doing. If I didn't understand RAII, or what a cache line is, or why branch misprediction costs you 15 cycles, no amount of AI could help me write a meaningful rulebook. The organist still needs to know music. The registrant handles the logistics so the organist can focus on playing.
But here's what I learned: the registrant needs a score to follow. When I gave AI vague instructions, I got vague C++. When I gave it forty-five specific techniques, mandatory patterns, prohibited patterns, measurable success criteria, and a benchmark framework, it gave me code I could review and ship. The precision of the output matched the precision of the input.
The organ is exactly as complex as it was before. The music demands it. But with a registrant who knows the score, one person can play it again.
. , a hard sci-fi serial where C++ concepts are the laws of physics.
SOCIAL SHARE CARD GENERATOR