SYLEN
AboutNewsConferenceMembershipDonate

Email updates

Conference, news, and membership updates by email.

Site

  • About
  • News
  • Membership
  • Waitlist
  • Donate

Conference

  • Conference 2027
  • Call for papers

Account

  • Create account
  • Membership details

SYLEN

  • Guidelines
  • Privacy
  • Terms

© 2026 Systems Leadership and Engineering Network. sylen.org.

Membership details →
Back to news
General SESource: ryanjk5.github.ioJuly 14, 2026

Boilerplate-Free Type Erasure via C++26 Reflection

The experimental library rjk::duck leverages C++26 reflection and metaprogramming features to automate type erasure. By utilizing compile-time annotations, automated vtable generation, and native overload resolution, the single-header library eliminates manual dispatch boilerplate without sacrificing runtime performance.

Implementing custom type erasure in C++ has historically required writing extensive virtual dispatch boilerplate or integrating heavy dependencies like Boost.TypeErasure or Folly.Poly. The experimental library `rjk::duck` eliminates these manual implementation overheads by leveraging the upcoming C++26 reflection APIs. Currently compiling on GCC with the `-std=c++26 -freflection` flags, this single-header library provides owning and non-owning semantics, interface composition, and operator support by offloading interface parsing and vtable generation to the compiler.

Parsing Interfaces via C++26 Annotations

The library uses C++26 annotations to declare interfaces. Users define a standard struct annotated with `[[=rjk::trait]]`. The library evaluates this annotation at compile time using the reflection operator `^^`, which yields a metadata token of type `std::meta::info`.

Using compile-time functions, `rjk::duck` queries these tokens to extract metadata. The trait parsing process filters the interface's members using an unprivileged access context, retaining only public, user-declared member functions while discarding constructors and data members. Each qualified member is then transformed into an internal representation called a tag, defined as `has_fn<"name", signature>`, which captures the function's identifier and type signature.

Automated Vtable Generation and Splice Operations

Rather than relying on manually defined virtual tables, the library generates the underlying `vtable` structure programmatically. Within a `consteval` block, it constructs a dynamic representation of the struct using `define_aggregate`.

The generator loops through the specified traits using the new C++26 `template for` expansion statement, which allows direct iteration over parameter packs. For each trait member, it strips cvref qualifiers, prepends an erased `void*` to the signature, and appends a corresponding function pointer to the member list via `data_member_spec`.

To instantiate the static vtable for a concrete type `T`, the library maps the slots of the generated `vtable` to the actual member functions of `T`. This mapping relies on the new splice operator (`[: expression :]`), which transitions from the reflection domain back to concrete C++ syntax, assigning the resolved function pointers directly to the vtable fields.

Type Erasure and Overload Resolution

At the execution boundary, concrete method calls must undergo type erasure. The library achieves this through an `erased_call` wrapper inside `vtable_fn_maker`. This wrapper accepts an erased `void self` argument, casts it back to `T`, and dispatches the call with `std::forward` arguments using `std::invoke`.

To determine which function to bind to, the library avoids reimplementing the C++ compiler's overload resolution logic. Instead, it utilizes a variadic `overload_set` structure that inherits from multiple callables and introduces their call operators into the scope via using-declarations. By compiling candidates into this native overload set, the library allows standard C++ overload resolution to handle the dispatch mechanics natively.

Read the original article at ryanjk5.github.io.