← На главную

Библиотека rjk::duck на C++26 reflection решает type erasure без шаблонов (только gcc)

14.07.2026 12:40 · hackernews

Библиотека rjk::duck решает давнюю проблему C++ — type erasure. Раньше для чего-то сложнее std::any или std::function приходилось писать сотни строк шаблонного кода либо тянуть тяжёлые библиотеки вроде Boost.TypeErasure или Folly.Poly. duck использует C++26 reflection и убирает всю боль, сохраняя производительность и гибкость.

Всё строится на новом синтаксисе C++26: вы описываете интерфейс как структуру с аннотацией [[=rjk::trait]], а библиотека сама генерирует обёртку. Например, объявили trait Container с методами size, empty, clear — и сразу можете складывать в rjk::duck<Container> то std::vector, то std::string, то std::map. Тип под капотом меняется во время выполнения, а вызываются методы как обычно: c.size().

Внутри duck проделывает несколько трюков. Сначала reflection превращает члены trait в теги вида has_fn<"foo", auto() -> int>. Потом на этапе компиляции генерируется vtable — структура с указателями на функции. Для этого используется consteval-блок и define_aggregate. Overload resolution не переизобретается — библиотека создаёт overload_set из candidate_wrapper, оборачивающих найденные методы, и компилятор сам выбирает подходящий.

Главная проблема — размер. Если в duck хранить обратные указатели на owner для каждой функции, объект раздувается. Решение — трюк с pointer-interconvertibility. Все vtable_function объявляются как пустые классы с no_unique_address, унаследованные через несколько обёрток. Благодаря стандарту, если первый член структуры имеет тип SomeType, reinterpret_cast от указателя на этот член к указателю на саму структуру — легален. Так duck получает this, не храня лишних байтов.

Библиотека работает и в constexpr-контексте, но с оговорками: reinterpret_cast в compile-time запрещён, хотя gcc-trunk такое пока позволяет. Для производительности можно указать perf_options — тогда часть функций встраивается прямо в объект, минуя косвенный вызов через vtable. Плата — несколько лишних байтов на каждый такой метод.

Сейчас duck поддерживается только на gcc с флагами -std=c++26 -freflection, но это живая демонстрация того, что reflection способен заменить ручную генерацию кода на что-то короче, безопаснее и настраиваемое. Исходники и онлайн-песочница на Compiler Explorer уже доступны.

Читать оригинал →