ycetl — a header-only library for building data structures at constexpr time and using them at runtime (C++20, no C++26 needed)
Hi r/cpp,
I've been working on ycetl, a small header-only library that takes on the "build a data structure at compile time, ship it as a runtime constant" problem.
The core trick is a multi-type memory backbone: instead of a std::byte* arena that requires void* → T* casts (forbidden in constant evaluation in C++20/23, only legal in C++26 via P2738), you enumerate the type set up front and the allocator becomes a tuple<Backend<T>...> indexed at compile time. Every allocation stays typed end-to-end. No erasure anywhere.
On top of that, the usual STL shapes — dynamic_array (vector-shaped), flat-sorted set/map, open-addressing unordered_set/unordered_map, the multi* variants, stack, priority_queue, span, bitset, unique_ptr, shared_ptr + weak_ptr. Every container is tested under static_assert(lambda()) and at runtime, with the same code.
Small taste — sieve at constexpr time, result baked into .rodata:
constexpr auto compute_primes() {
primes_result<32> out{};
ycetl::default_memory<bool, std::pair<int,int>> mem; // working memory
auto sieve = mem.allocate<bool>(101);
auto records = mem.allocate<std::pair<int,int>>(32);
// ... sieve + collect into records + copy into out ...
return out; // result memory
}
constexpr auto baked = compute_primes();
static_assert(baked.records[24\].first == 97);
There's also a worked example that drives libclang against dawn/webgpu.h and emits both a Python ctypes binding and a constexpr C++ tree of the same API — same source, two consumers.
Where it sits next to C++26. The "less-transient constexpr allocations" work (P3032) + the void* cast (P2738) tackle the same problem from the opposite direction: make the compiler smart enough to
promote std::vector-shaped allocations to static storage. ycetl is the explicit-control side of that trade — you write the type set and the result-shape, in exchange you get a transparent layout, no
void* round-trips, no proof-obligation on the compiler, and it runs on shipping GCC 12+ / Clang 16+ today. There's a section in the README laying both sides out honestly; I'd genuinely like to hear which trade people here prefer.
Honest about gaps: a few headers from an earlier design (vector.hpp, list.hpp, basic_string.hpp) haven't been ported and their tests are gated off. No real deque/queue yet. Single-threaded by design the smart-pointers use non-atomic counts.
Repo: https://github.com/zokrezyl/ycetl
Critique welcome — especially from anyone who's tried this kind of design and hit walls I haven't yet.
https://redd.it/1tmdbr7
@r_cpp
Post #25270
14