170 похожих чатов

А можно ссылку что такое лупхолы? В целом мне кажется

данная задача нерешаема без скатывания в RTTI...

22 ответов

51 просмотр

Про сами лупхолы можно послушать здесь. И посмотреть мой репозиторий. В особенности комментарии здесь

можно еще посмотреть на эту библиотеку https://github.com/vampyrofangclub/horrifiction (40 строчек кода) - там в ридми показан пример как можно применять библиотеку для стирания типов и рантайм-полиморфизма

Денис-Берёзкин Автор вопроса
Богдан
можно еще посмотреть на эту библиотеку https://git...

Спасибо, посмотрю. Но не понял зачем отдельная библиотека для рантайм-полиморфизма? RTTI ведь стандартный есть...

Текущий RTTI в С++ ограничен сишным интерфейсом (требующий конкретные типы) - то есть это значит что ты не можешь например работать полиморфно с рантайм-объектами у которых методы возвращают auto-тип или параметры принимают auto-тип. Например допустим я хочу сохранять в контейнере объекты имеющие метод auto draw(auto lambdaCallback) а потом вызывать этот метод для каждого объекта в контейнере не зная его настоящий тип. Или например хочу сохранить лямбду в std::function но сейчас это невозможно в случае если у лямбды будет тип возврата auto или она принимает auto-параметр. А вот рантайм-полимформизм через эту технику лупхолов делает все это возможным

Богдан
Текущий RTTI в С++ ограничен сишным интерфейсом (т...

Это же все поломается если делать в разных единицах трансляции, разве нет?

Денис Михайлов
Это же все поломается если делать в разных единица...

Да, конечно. Но можно смотреть на это как на рефлексию которая точно так же будет в С++26 ограничена одной единицей трансляции

Но кстати конкретно вот такое применение лупхолов для рантайм-полиформизма можно было бы заменить фичей которая называется "давайте разрешим шаблонные виртуальные методы" и тогда это потенциально может работать между разными TU (но в свою очередь это усложняет ABI и требует от линкера дополнительного процесса по мерджингу виртуальных таблиц из разных единиц трансляции)

Богдан
Но кстати конкретно вот такое применение лупхолов ...

Тут можно подумать в сторону того что в модных языках называется boxing. То есть можно по простому сохранить пару object+function. Тогда функции реализующие trait можно писать отдельно.

Что касается техники лупхолов то для объектов с методом "auto draw(auto lambdaCb)" не будет происходить "мономорфизации в стиралке типов", "не требует наличие JIT" и не создает "комбинаторного взрыва в вызывающем коде" По сути техника рантайм-полиморфизма через лупхолы автоматизирует то что и так приходится делать вручную. Например если ты хочешь хранить в контейнере объекты двух типов имеющие шаблонный метод "auto draw(auto lambdaCb)" struct Rect { int width; int height; auto draw(auto labmdaCb){ ... } }; struct Circle { int radius; auto draw(auto labmdaCb){ ... } } то тебе придется объявить некую Shape-обертку чтобы завернуть в нее объект Rect или Circle перед добавлением в контейнер попутно сохранив числовой айдишник типа int TypeId; template<typename T> auto GetIdForType = [](){ return TypeId++; }() struct Shape { void* ptr; int typeId; Shape(auto obj){ ptr = obj; typeId = GetIdForType<decltype(obj)>; } } auto vec = std::vector<Shape>(); vec.push_back(Shape(new Rect(10, 10)); vec.push_back(Shape(new Circle(20)); и дальше тебе нужно будет вручную перебирать возможные типы на совпадение с typeId у объекта Shape for(auto shape: vec){ if(shape.typeId == GetTypeId<Rect*>){ auto obj = static_cast<Rect*>(shape.ptr); //теперь у нас статический тип и мы можем вызывать шаблонный метод draw() auto res = obj->draw([](...){...}); } if(shape.typeId == GetTypeId<Circle*>){ auto obj = static_cast<Circle*>(shape.ptr); //теперь у нас статический тип и мы можем вызывать шаблонный метод draw() auto res = obj->draw([](...){...}) } } Вот и все. Вот пример того как можно реализовать на С++ рантайм-полиморфизм для методов с auto-возвратом или с auto-параметрами без всяких лупхолов И техника рантайм-полиморфизма через лупхолы в данном примере будет иметь точно такой же оверхед - то есть все что будут делать лупхолы (в случае использования этой библиотеки) так это за юзера выполнят эти две строчки на рантайм-проверку typeId для типа Circle и Rect и юзеру всего лишь нужно будет передать лямбду получив параметром объект конкретного типа for(auto shape: vec){ shape.visit([](auto obj){ //теперь obj у нас статический тип и мы можем вызвать шаблонный метод draw() auto res = obj->draw([](){...}); }) } И поскольку мы выяснили что лупхолы не добавляют оверхеда и всего лишь автоматизируют то что разработчик и так вынужден писать вручную то дальше можно рассказать в чем прелесть лупхолов (помимо того что убирает болерплейт ручного матчинга). И прелесть механизма стирания типов через лупхолы заключается в возможности заматчить тип который разработчику неизвестен, например когда мы возвращаем разные лямбды из функции по рантайм-условию auto getFn(bool flag) { if (std::rand() % 2) { return Any(new auto([=](auto val) { return val + 1; })); } else { auto someVal = 10; return Any(new auto([=](auto val) { return someVal + val; })); } } здесь возвращаемый тип лямбды зависит от того будет ли в рантайме делиться на 2 некое рандомное число и ты можешь написать подобно обертки Shape (где сохраняешь void* ptr и int typeId) аналогичную обертку Any для лямбд но дальше у тебя тупик потому что ты не знаешь на какой тип нужно матчить typeId int main(){ auto any = getFn(); if(any.typeId == GetTypeId<??????>){ ... } } а вот механизм лупхолов как раз таки позволяет узнать этот тип и автоматически проверить совпадение typeId и юзеру всего лишь нужно будет передать лямбду где он получит конкретный объект лямбды аргументом int main(){ auto any = getFn(); any.visit([](auto fn) { std::cout << (*fn)(42) << "\n"; //43 std::cout << (*fn)(42.42) << "\n"; //43.42 }); auto any = getFn(); any2.visit([](auto fn) { std::cout << (*fn)(42) << "\n"; //52 std::cout << (*fn)(42.42) << "\n"; //52.42 }); }

Так я уже выше сказал - да, здесь ограничение на то что это будет работать внутри одной единицы трансляции (или точнее могут быть разные TU, но эти типы для которых нужно стереть тип должны быть объявлены в хедерах) собственно как и у будущей рефлексии. Если аргумент про JIT касался возможности работы разных единиц трансляции то тогда пардон, не так понял

а как иначе?

Богдан
а как иначе?

и как это люди обходятся без реализации ваших идей .... загадка .... 🤷🏻‍♂️

Богдан
Так я уже выше сказал - да, здесь ограничение на т...

типы не просто должны быть объявлены в хедерах у каждой единицы трансляции должен совпадать порядок в котором всё множество типов регистрируется в залупхоле у стиралки (точнее даже не порядок, а мнение компилятора о том в каком порядке произвести залупхольное волшебство, чтобы id типов совпали, их порядок в ручных vtable и прочее) иначе как минимум пол дня весёлой отладки странных сегфолтов обеспечены (и у меня уже были пару раз)

Boris Usievich
и как это люди обходятся без реализации ваших идей...

страдаем круглые сутки и ждём не дождемся когда он их начнёт писать уже не сюда, а в рассылку WG21

Гражданин Котейко
типы не просто должны быть объявлены в хедерах у к...

порядок регистрации совпадать не должен но есть нюансы с тем что матчинг может произойти раньше чем регистрация (как никак это все же костыльная техника) но этим можно управлять если понимать как происходит порядок вывода типов и инстанциирования у функций по коду программы. Ну и никто не предлагает всю архитектуру строить поверх вот этой техники но применять ее в ограниченном порядке, где-то локально в одном или парочке мест вполне возможно

Богдан
порядок регистрации совпадать не должен но есть ню...

ну локально в парочке мест можно и без этого пострадать

Богдан
Что касается техники лупхолов то для объектов с ме...

а что мешает забиндить лямбду так, чтобы она вызывалась по универсальному интерфейсу? Внутри себя она знает типы, поэтому там можно оперировать с шаблонами

Похожие вопросы

Обсуждают сегодня

Anyone here suffers from unexplained aural migraines, who would be up for talking for a bit? Doesn't *have* to be aural, but I am not asking about headaches, I mean actual mi...
Martin Rys
55
подскажите пожалуйста, как мне освободить результат записанный в переменную result? в чем проблема подскажите если МОЖЕТЕ?
Михаил Helper
28
есть тут кто-то , кто только начал изучать си? если проходите курс на степике или как-то сами изучаете, пишите, может, скооперируемся?..
Eule
25
Слушайте, ещё такая интересная задачка. Сделан аудит действий пользователей через триггеры в базе, соответственно каждый пользователь имеет свой логин и пароль в базе. Это пре...
Сергей Бычков
12
Кстати, раз про скачивание файлов разговор зашел) Сделал бота для себя (транскрибирующего и суммаризирующего встречи) но не ожидал что за 2 месяца 10к пользователей набежит😅...
Andrey Obolenskiy
8
вопрос по москвину - не понимаю вот такого вопроса похоже Сколько разных всегда завершающихся функций с типом a -> a -> b -> a -> a можно реализовать? Две функции одинаково...
Fedor
11
Скажите, тут нет проблемы? IMyInterface1 = interface function GetInterface2: IInterface2; ... function TMyInterface.GetInterface2: IInterface2; begin Result := TI...
Ruslan aka DUDE
18
я не магистр хаскеля, но разве не может лейзи тип конвертнуться в не-лейзи запросив вычисление содержимого прям при инициализации?
deadgnom32 λ madao
100
Утра доброго. Просветите пожалуйста. Хочу сделать rest сервер на делфи. Посмотрел 3 фреймворка: dmvc, Mars, mormot. Ни в одном из них не упоминается ассинхронная обработка вхо...
Сергей Бычков
10
Как попросить stack install делать executable без .exe на винде?
Danila Danko
9
Карта сайта