cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
89 stars 0 forks source link

Недостающий инструмент динамического полиморфизма в стандарте #514

Open kelbon opened 2 years ago

kelbon commented 2 years ago

Мотивация частично описана тут: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0957r6.pdf И тут : https://github.com/kelbon/AnyAny Если очень кратко - текущие инструменты динамического полиморфизма недостаточны : виртуальные функции и код, который с ними получается, не отражает реальных намерений программиста (бесконечные поинтеры, управление памятью, наследование и проч.), std::any практически бесполезен (единственная его польза это деструктор, то есть гарантия что что-то удалится). std::variant уже гораздо лучше, но неудобен в использовании, плохо расширяем(если добавляется новый тип приходится менять все места его использования), когда типов много визиторы в реальном коде становятся громадными, большие проблемы с исключениями(valueless_by_exception), а если написать std::visit с двумя визиторами можно раздуть бинарник до гигабайтов(что мягко говоря неочевидно для новичков да и опытных...)

Моё предложение заполняет нишу, где variant плох, а виртуальные функции ужасны. Там, где реально нужен полиморфный объект

Представим что нужен класс машины, где есть двигатель и его можно менять на рантайме. Кажется наилучшее выражение мысли в коде это

struct Machine {
  any_engine engine_;
};

И с моим предложением реализация выглядит так:

template<typename T>
struct Go {
  static int do_invoke(T self, int value) {
   self.Go(value);
   return value * 4;
  }
}

using any_engine = any_with<Go>; // здесь может передаваться произвольное количество методов

Вызывать методы можно либо через invoke\<Go>(engine); либо написав в классе метод (и тогда будет выглядеть как обычный класс), см. реализацию и readme. На мой личный взгляд интерфейс гораздо удобнее чем у предлагаемого std::proxy, при этом у меня есть строгая гарантия исключений(которой нет в std::proxy) и value семантика, реализация судя по бенчмаркам практически такая же по производительности как и variant Аллокатор и размер SOO буфера регулируемы, можно добавлять любое количество методов, реализовывать передачу self по копии(кстати выше в примере с машиной так и происходит) и многое другое

Реализация тут:

https://github.com/kelbon/AnyAny