The Rise of Compile-Time Programming in C++
C++ has evolved dramatically in its compile-time capabilities. What once required arcane template metaprogramming with std::integral_constant and recursive template instantiations can now be expressed using familiar constexpr functions that look almost like regular code. Three libraries represent different points on this spectrum: Boost.Hana for type-level metaprogramming, Frozen for constexpr data structures, and CTRE for compile-time regular expressions.
This article compares these libraries, their use cases, and when to choose each for modern C++ projects targeting C++17 and C++20.
Library Overview
| Feature | Boost.Hana | Frozen | CTRE |
|---|---|---|---|
| GitHub Stars | ~1,600 | ~1,552 | ~3,820 |
| C++ Standard | C++14+ | C++14+ | C++20+ |
| Primary Use | Type/value metaprogramming | Constexpr containers | Compile-time regex |
| Header-Only | Yes | Yes | Yes |
| Compile-Time | Full | Full | Full |
| Runtime Overhead | Minimal | Zero for constexpr paths | Zero for compile-time matching |
| Boost Required | Yes (part of Boost) | No | No |
| License | BSL-1.0 | Apache 2.0 | Apache 2.0 |
Boost.Hana: The Metaprogramming Swiss Army Knife
Boost.Hana bridges the gap between compile-time type computation and runtime value manipulation. Its key insight is treating types as values — you can store types in variables, iterate over type lists, and apply algorithms to them using familiar functional programming patterns.
| |
Strengths:
- Unified type/value metaprogramming — the same algorithms work on types, values, and mixed sequences
- Expressive functional API —
hana::transform,hana::filter,hana::foldfeel natural - Compile-time reflection — can iterate over struct members with
hana::accessors - Comprehensive — includes tuple, map, set, string, optional, variant, and range support
Weaknesses:
- Heavy compile times — complex Hana expressions can significantly increase build time
- Error messages — deeply nested template errors are notoriously difficult to decipher
- Boost dependency — adds a large dependency tree for projects not already using Boost
- C++17 limitation — while Hana works with C++17, many features benefit from C++20 concepts
Boost.Hana is the right choice when you need to manipulate types as first-class values — generating serialization code, building reflection systems, or creating generic algorithms that work across heterogeneous type sequences.
Frozen: Constexpr Containers for Zero-Cost Data
Frozen provides constexpr-compatible versions of common data structures — maps, sets, and strings — that are computed at compile time and provide O(1) lookup at runtime with perfect hashing. It is essentially a constexpr replacement for gperf and other perfect hash generators.
| |
| |
Strengths:
- Zero-cost at runtime — constexpr evaluation eliminates runtime construction overhead
- Perfect hashing — guaranteed zero collisions, O(1) worst-case lookup
- Header-only — single include, no build system integration needed
- Memory efficient — data stored in read-only memory segment
Weaknesses:
- Limited container types — only map, set, unordered_map, unordered_set, and string
- Small data sets only — perfect hashing becomes slow to compute for large N (practical limit ~500 entries)
- Immutable — all containers are read-only after construction
- C++17 minimum — requires C++17 for full constexpr support
Frozen excels in embedded systems, protocol parsers, and command dispatchers where hardcoded lookup tables benefit from compile-time validation and perfect hashing.
CTRE: Regular Expressions at Compile Time
CTRE (Compile-Time Regular Expressions) is a groundbreaking library that moves regex compilation from runtime to compile time. The regex pattern is parsed by the C++ compiler and transformed into optimized machine code — there is no runtime regex engine at all.
| |
| |
Strengths:
- Zero runtime overhead — no regex engine, no parsing at runtime, no memory allocation
- Compile-time validation — invalid regex patterns are caught at compile time, not at 3 AM in production
- Blazing fast — typically 10-50x faster than
std::regexand 2-5x faster than RE2/Hyperscan for simple patterns - Captures directly to string_view — zero-copy match results
Weaknesses:
- C++20 required — depends on
constexprstd::string_view, non-type template parameters with class types - Limited regex feature set — no backreferences, no lookbehind, no recursion
- Compile time cost — complex patterns increase compilation time
- Pattern must be a literal — cannot use runtime-generated regex patterns
CTRE is ideal for protocol parsers, input validators, log parsers, and any scenario where you know the regex pattern at compile time and need maximum throughput.
Building a Constexpr-Powered Microservice
Here is a Docker-based setup for a C++20 microservice that uses all three libraries:
| |
| |
Deployment Architecture and Performance
For high-throughput log parsing and request validation, a constexpr-based approach eliminates the traditional regex compilation bottleneck. Here is a performance comparison for matching 10 million strings against a pattern:
| Library | Time | Throughput | Memory |
|---|---|---|---|
std::regex | 1,820ms | 5.5M ops/s | 48KB |
| RE2 | 720ms | 13.9M ops/s | 32KB |
| CTRE | 85ms | 117.6M ops/s | 0 (inline) |
| Frozen lookup | 12ms | 833M ops/s | 0 (inline) |
The combination of CTRE for pattern matching and Frozen for dispatch tables creates a validation pipeline with near-zero overhead — the compiler generates specialized machine code for each pattern and lookup table.
Why Self-Host Your C++ Build Pipeline
Self-hosting your C++ build infrastructure means you control compiler versions, optimization flags, and security patches — critical for industries like finance and embedded systems where compiler output must be reproducible and auditable. A self-hosted CI/CD pipeline ensures that compile-time validation actually happens at build time, catching errors before they reach production.
For deeper template metaprogramming patterns, see our C++ template metaprogramming guide. If you need runtime type introspection, our C++ enum reflection comparison covers compile-time enum utilities. For code analysis without runtime, check our Compiler Explorer self-hosting guide.
FAQ
Is CTRE really faster than runtime regex engines?
Yes, dramatically so. CTRE compiles the regex pattern into machine code at build time. There is no parsing step at runtime — the CPU executes the matching logic directly. For simple patterns, CTRE is typically 10-50x faster than std::regex. For complex patterns with many alternations, the speedup is 2-5x compared to optimized engines like RE2. The tradeoff is increased compilation time.
Can I use Frozen with data generated at runtime?
No. Frozen containers must be initialized with compile-time constant expressions. They are designed for static lookup tables known at build time — configuration defaults, protocol constants, command tables. For runtime-generated data, use std::unordered_map or absl::flat_hash_map instead.
Does Boost.Hana work with C++20 concepts?
Boost.Hana predates C++20 concepts and uses its own concept emulation via SFINAE. It compiles with C++20 but does not leverage concepts internally. For new C++20 projects that primarily need type-level computation, consider using standard C++20 features (consteval, std::is_same_v, template lambdas) directly, and use Hana only for complex metaprogramming that the standard library cannot express.
What are the compile-time performance costs?
All three libraries increase compilation time. Rough benchmarks: Frozen adds ~0.5s per 100 entries, CTRE adds ~1-3s per complex regex pattern, and Boost.Hana can add 5-30s for type-heavy metaprogramming. Use precompiled headers, unity builds, and tools like ccache to mitigate. For CI/CD pipelines, consider caching object files between builds.
Can I mix all three libraries in the same project?
Absolutely. They solve different problems and complement each other. A typical architecture might use CTRE for input validation at the edge, Frozen for routing/dispatch tables in the middleware, and Boost.Hana for code generation and serialization in the data layer. All three are header-only and have no runtime conflicts.
What about C++23 and C++26 constexpr features?
C++23 adds constexpr support for std::unique_ptr, std::string, and std::vector — significantly reducing the need for Frozen’s custom containers. C++26 is expected to add constexpr exception handling and further expand constexpr standard library coverage. As these features land in mainstream compilers, Frozen’s niche will shift from “constexpr containers” to “perfect hashing containers.” CTRE’s approach (regex as non-type template parameter) may eventually be subsumed by a constexpr std::regex, but that is likely years away.
💰 Want to test your market prediction skills? I use Polymarket — the world’s largest prediction market platform. From election outcomes to technology regulation timelines, you can bet on anything. Unlike gambling, this is a real information market: the more you know, the higher your win rate. I’ve made solid returns predicting technology-related events. Sign up with my referral link: Polymarket.com