Нашли или выдавили из себя код, который нельзя назвать нормальным,
на который без улыбки не взглянешь?
Не торопитесь его удалять или рефакторить, — запостите его на
говнокод.ру, посмеёмся вместе!
Хренево, объекты и классы в J то же, что и локали (неймспейцы по вашему, но их можно создавать в рантайме). Через жопу 4!:1 (описани https://www.jsoftware.com/docs/help807/dictionary/dx004.htm) можно получить имена в текущей локали (например 4!:1]0 получит имена существительных), но перечисляются только имена только в текущей локали, из локали которой наследуемся получить не могем, и имена родительской или унаследованной локали также получить не могем. Хоть имена локалей тем же способом (4!:1]6) и можно получить, но у них отдельный и единый неёмспейс и в списке приходят имена сразу всех имеющихся локалей. Единственное что нарыл (ну натыкал в jcоcноле): при создании объекта у него создаётся поле COCREATOR, в котором хранится имя локали в котором его создали.
Но для того, чтобы в рантайме выбрать класс это и не нужно.
> Most programming languages’ grammars fall into the category of Context-Free Grammar (CFG), or sometimes Context-Sensitive Grammar (CSG). What about C++? It turns out parsing C++’s grammar is literally undecidable. In other words, if you have a compiler that parses all valid C++ sources perfectly, you have solved the Halting Problem.
Для написания 100% корректного компилятора C++ надо решить проблему остановки. Какой багор )))
Надо было им новые скобочки изобрести, а не использовать хуйню "больше-меньше". Например, через комбинацию обычных скобочек с какой-нибудь хуйней, которая не встречается. Типа @%$( как открывающая и )@%$ как закрывающая. Можно даже вводить сколько угодно видов скобочек, типа вот такого пизданатства
Тогда для их ввода надо будет какие-то хоткеи придумывать, или специальную раскладку. Да и юникод может закончиться. Еще б сделать, чтобы скобочки перегружать можно было и определять как некие новые как бы операторы, и чтоб с неймспейсами. Например, на какой-нибудь метушне можно описать что у нас теперь есть скобочки типа @0%$( и )@0%$ которые такую-то хуйню делают, и можно или делать my_namespace::@0%$( некаяхуйня my_namespace::)@0%$
или сделать using namespace my_namespace; и тогда просто@0%$( некаяхуйня )@0%$ писать можно. Это ж какой простор для творчества!
Потому что кресты и так хуёво читаются, а тут ещё искать в середине файла эти using'и... Сейчас в адекватных случаях они всё-таки стоят или прям сверху файла или в начале скоупа.
Да и вообще, стек это говно для анскиллябр, ведь настоящие Цари знают, что единственная полезная структура данных - массив. Надо делать тьюринг-полный язык для манипуляций с массивом неймспейсов, а не просто какой-то там pop и delete.
Это вообще суть крестов, взять какую-нибудь тупую херню типа шаблонов, и раздуть ее до уровня маразма
Помнится, я такую питушню для переменных писал: https://github.com/1024--/peetooshnya/tree/master/varprepr
С этим препроцессором можно переиспользовать имена переменных, создавая микроскоупы. Там есть реализации для кода на C, Python или JS, можно добаалять свои.
Поправь меня, если чио: createTypeImpl просматривает пачку классов, проверяя вхождение строки в поле, и когда находит, возвращает другой связанный с ним класс?
Рефлексия считается не очень красивым решением: она не очень быстрая, и может быть не очень безопасная. Так что использовать ее лучше для инфраструктурного кода только.
Например, ты можешь взять Spring (или другой контейнер) и там будет такой API.
Но если ты встроишь рефлексию посреди бизнес-логики, то на тебя посмотрят косо.
Создать объект, класс которого определяется строкой в рантайме.
Юзер вводит «first type» — создаётся объект типа «SE_0»; вводит «second type» — объект типа «SE_1» и так далее.
Реальный пример: есть N типов пакетов (сетевых), различающихся по заголовку (строка в начале). Для каждого пришедшего из сети пакета нужно создать соответствующий объект, передав в его коньструктор данные из пакета. Ситуация усугубляется тем, что заголовок отделяется от данных разными символами: где-то пробелом, где-то новой строкой, а в одном пакете — вообще обратным слэшем. Для дополнительного веселья в некоторых видах пакетов данных может вообще не быть (просто строка заголовка), а для некоторых — может быть, а может и не быть.
я бы сделал массив читтателей.
Каждый читатель читал бы заголовок и говорил бы "О! Мой пездюк! Вот тебе для него абект"
или
"Первый раз вижу, вот тебе null".
Итерировался бы до первого ненулевого значения.
Бойлерплейт в читателях уменьшил бы посредством шаблонов
Можно, но тогда возникает проблема с засовыванием в эту карту значений (это нужно сделать для каждого класса, и желательно с как можно меньшим бойлерплейтом).
В скриптушне я бы просто сделал декоратор а-ля @register (выше пример), а вот с крестами проблемка выходит — сделать инициализацию рантайм-карты без явного перечисления типов и строк в createObjectByName() проблематично*.
Наскока я понимаю в сишечке (и вероятно в кристах) подход должен быть такой: если ты не хочешь писать бойлерплейт руками, и не можешь (или не хочешь по причинам перформансе) заставить рантайм сделать это за тебя, то ты используешь генерилку кода.
Самое страшное это писать одно и тоже знание в нескольких местах.
Потому в генерилке ты пишешь его ОДИН раз, а дальше оно само генерийет бойлерплейт где хоть 100500 раз это знание написино.
Когда я паршу текст -- я описываю грамматиики и потом лексы с бизонами за меня генерят код с говном
Ты пишешь парсер сетевого протокола. Это тоже самое.
Тебе нужно описание этого протокола в каком-то формате, где к каждому типу пакета привязан класс.
И геренилка кода, которая эту хуйню за тебя сгенерит.
Да я уже нахуевертил эту генерилку на шоблонах (по типу того, что в посте) и мокросах (намокросил табличку соответствия пакетов, в сущности, это и есть то самое описание), благо что там всего двенадцать типов пакетов есть.
о
я пирдумал, правдла для сисечки, а не для крестов (на кресты сам переведи).
Собираешь модули: petuh.dll(so), krestuh.dll(so) итд. В каждом делаешь функцию init().
Потом из строки строишь путь, загружаешь через LoadLibrary (dlopen), и передаешь управление в init.
В старых заставках показывали «А320», хотя голос диктора говорил про «Бройлер-747». Потом видеозапись «А320» поменяли на компьютерную графику самолёта с надписью «Бройлер-747». Вроде даже старые серии перемонтировали.
А если сделать иерархию base <|--- pituz<S0> <|--- S0?
Тогда
* в base можно добавить static base *pituxes[PITUXES]; static size_t pituxes_length = 0;
* в pituz<T> добавить статический pituz<T>::bagor, который делает
pituxes[pituxes_length++] = new T;
* в pituz<T> добавить виртуальную питушню pituz<T>::insert = \m -> m[тут взять имя класса у рттиуха] = this
* бормандов instances заполнять как map (flip insert m) pituxes.
То есть за счёт питушино-рекурсивного наследовательного паттерна прописать всем детям питушню для добавления себя в питухов на статическом этапе, а также - себя и своего имени в выбранную мапу, когда будет мапа. Когда статика отработает, и все питухи инициализируются, можно будет воспользоваться STL. В программе берём мапу и форычим питухов, прося их добавиться в мапу.
Тогда каждый новый питух должен только унаследоваться от pitux<новый питух>, и он ватоматически добавится куда надо.
Авторегистрация - это потеря гибкости, на самом деле. Заполненная вручную мапа хоть и копипаста, но ты можешь поддерживать несколько её вариантов (для разных версий протокола, к примеру).
Я перечитал этот тред, вроде понял проблему. Видимо, вчера очень хотелось спать, и поэтому внимательно не прочитал.
Я всё равно не чувствую весомости потери гибкости. Получать классы по именам надо не в каждом проекте, а вот чтобы ещё несколько разных групп было - вообще редкий вариант.
> потеря гибкости
Ну не знаю, можно тогда из pituxes нагенерировать новые питушни по вкусу.
Или сделать pituz<T, GROUP1 | GROUP3 | PITUXI> - какую-то битушню с группами, и автоматически распихивать по группам.
Хотя, я не знаю, зачем вообще весь этот пердолинг и какие подмножества питушни могут понадобиться.
> связный список
Как мне кажется, долговато кодить для статической питушни. да и массив - царская питушня.
Кстати, malloc может на этапе статический инициализации быть не готовым к работе?
>И ты получишь ошибку конпеляции если что-то из этого забыл запилить.
Если я забуду добавить в мапу, ошибки компиляции не будет. Хотя классы будут потомками Base и всё такое.
В случае с наследованием от вореционизатора я либо сразу не буду потомком Base, и компиляцию прикроют, либо буду и потомком, и сяду в мапу.
Мапа плоха тем, что для добавления в неё нового типа нужно открыть файл с ней (какой-нибудь PituhFactory.cpp) и явно прописать новый класс. Это, во-первых, неудобно (править один файл легче, чем два), а во-вторых, если ты забудешь добавить в мапу новый тип, то узнаешь об этом только после запуска (а если не повезёт — то после запуска у юзера).
Так с шаблоноговном это тоже легко: поддерживается только те типы, которые описаны в TypesEnum. При этом если добавить тип в TypesEnum, а зарегистрировать в Registry забыть — всё отвалится во время компиляции.
> в pituz<T> добавить статический pituz<T>::bagor, который делает
На этом этапе проблема. В крестах статических блоков инициализации (как в ЙАЖА, например) нетути, можно только городить ненадёжную и нестабильную питушню вроде «static auto huj = static_initialization_function()», но так возникают проблемы от порядка инициализации (я вот хз, например, будет ли инициализирован CRT на момент вызова static_initialization_function()) и до множественной инициализации (если разместить функцию в .h).
Хорошо, тогда пусть будет
* массив metuxes не указателей, а просто объектов (чтобы без malloc и прочей питушни)
* bagor с помощью placement new раскатывает в metuxes объект creator<T> с виртуальным методом который создаёт и помещает unique_ptr<T> в выбранную мапу.
Думаю, у всех креаторов будет размер как у указателя на vtable, поэтому их можно будет перебирать по значению и вытягивать из массива питухов реинтерпрет питухом.
> bagor будет делать
Главный вопрос в том, как он это будет делать. Нормальных статических блоков-то не завезли, поэтому нам придётся дёргать этот код в рантайме, а для этого надо, опять же, проитерироваться по всем зарегистрированным creator<T>.
Нахуевертил поебень по мотивам, которая должна регистрировать тип, отнаследованный от BaseRegistrator<T> (какой «CRTP», кстати!): https://wandbox.org/permlink/0RWVZIDjQTYNjbvU. Есть две проблемы:
1. Статический член (в твоей нотации — creator_for_creator) не инициализируется, если к нему явно не обратиться.
2. Этот же самый код, собранный через «clang», падает с сегфолтом. «Gcc» и «MSVC» работают (но согласно первому пункту).
Собственно, как я и говорил в верхних комментах, статическая иницализация в крестах — говно ёбанное. То ли дело ЙАЖА.
Есть опасение, что ДОБРОЕ ОПРЕДЕЛЕНИЕ ДОБРАЯ ПЕРЕМЕННАЯ ИДЕНТИФИКАТОР ИДЕНТИФИКАТОРЕК В ЧЕСТИГлавная карта может как-то плохо себя вести. У меня был пост про выстрел в ногу со статушнёй: http://govnokod.ru/15263
Поэтому я предлагал изначально на всякий случай питушить в простой массив.
> что будет делать put_me()
Создавать объект и добавлять в бормандову мапу
> и как будет реализована createObject(string name)?
return instances.at(name);
где instances - бормандова питушня из второго комментария.
> А там, где нужна мапа - делать std::map<.....> m; fill_your_map(m);
std::map<.....> instances; fill_your_map(instances);
Если попердолить это выражение, компиляторы перестают выдавать предупреждение, а код всё ещё работает.
Перенёс пердолинг с STL и прочей питушнёю сложнее царского массива в main, как и планировал.
Правда, я что-то не то сделал, и код со string_view сломался - заменил на string.
Вот, в итоге заставил работать эту питушню: https://wandbox.org/permlink/KBmYlLmfVWyInOxk
Из-за синглтонства пришлось unique_pitux заменить на shared_pitux, сделал поэтому вспомогательный pointer<T>
Но в Ди с рефлексией проще. Тупо перечислил в цикле все имена в модуле, нашел потомков Base и создал.
Проклинаю васю
Но для того, чтобы в рантайме выбрать класс это и не нужно.
З.Ы. Где-то у меня был пример, который в зависимости от значения константы компилится либо как шаблон либо как операторы сравнения.
> Most programming languages’ grammars fall into the category of Context-Free Grammar (CFG), or sometimes Context-Sensitive Grammar (CSG). What about C++? It turns out parsing C++’s grammar is literally undecidable. In other words, if you have a compiler that parses all valid C++ sources perfectly, you have solved the Halting Problem.
Для написания 100% корректного компилятора C++ надо решить проблему остановки. Какой багор )))
и так далее. Наверняка в каком-нибудь стандарте появится и такая поебень
или сделать using namespace my_namespace; и тогда просто@0%$( некаяхуйня )@0%$ писать можно. Это ж какой простор для творчества!
Да, я знаю что можно в пределах какой-то одной функции/метода и пр. эту хуйню с юзингом сделать, но это не то.
АХАХАХАХ
Ждём.
Во! Я думаю теперь точно примут пропозал.
Ну и using std = default на случай если ты затёр std чем-то другим и теперь хочешь вернуть на место.
Лучше сделать pop(n). Типа, если несколько раз перезатер, можно на столько-то раз откатиться.
using std = pop(2);
Это вообще суть крестов, взять какую-нибудь тупую херню типа шаблонов, и раздуть ее до уровня маразма
С этим препроцессором можно переиспользовать имена переменных, создавая микроскоупы. Там есть реализации для кода на C, Python или JS, можно добаалять свои.
https://govnokod.ru/26283#comment518451
> Еще выяснилось, что я не итератор, а шаблон. Ну и черт с ним, подумал я.
Поправь меня, если чио: createTypeImpl просматривает пачку классов, проверяя вхождение строки в поле, и когда находит, возвращает другой связанный с ним класс?
В жабах с шарпеями же только рефлексией. В скриптогавне то в любом можно
В йпже можно найти классы по аннотации, но инстанциировать их все равно будет рефлексия
Например, ты можешь взять Spring (или другой контейнер) и там будет такой API.
Но если ты встроишь рефлексию посреди бизнес-логики, то на тебя посмотрят косо.
Вроде скоро в джаву завезут умные енумы, которые могут быть разными классами, тогда станет прочще
Юзер вводит «first type» — создаётся объект типа «SE_0»; вводит «second type» — объект типа «SE_1» и так далее.
Каждый читатель читал бы заголовок и говорил бы "О! Мой пездюк! Вот тебе для него абект"
или
"Первый раз вижу, вот тебе null".
Итерировался бы до первого ненулевого значения.
Бойлерплейт в читателях уменьшил бы посредством шаблонов
?
ну потом ее вызываешь, и она создает тебе нудный класс?
В скриптушне я бы просто сделал декоратор а-ля @register (выше пример), а вот с крестами проблемка выходит — сделать инициализацию рантайм-карты без явного перечисления типов и строк в createObjectByName() проблематично*.
*Можно, но заёбисто.
Самое страшное это писать одно и тоже знание в нескольких местах.
Потому в генерилке ты пишешь его ОДИН раз, а дальше оно само генерийет бойлерплейт где хоть 100500 раз это знание написино.
Когда я паршу текст -- я описываю грамматиики и потом лексы с бизонами за меня генерят код с говном
Ты пишешь парсер сетевого протокола. Это тоже самое.
Тебе нужно описание этого протокола в каком-то формате, где к каждому типу пакета привязан класс.
И геренилка кода, которая эту хуйню за тебя сгенерит.
ЗЫ: Я нагуглилъ
http://www.icsi.berkeley.edu/pubs/networking/binpacIMC06.pdf
https://github.com/zeek/binpac
беркли хуйни не посоветует
Как бы то ни было, шоблонное говно я буду юзать в последнюю очередь.
А из DSLя автоматически нагенери пачку switch/if.
Нативно такие штуки хорошо писать толко на скриптоговне: там это вообще всегда их коробки и хорошо работает
> Нативно такие штуки хорошо писать толко на скриптоговне: там это вообще всегда их коробки и хорошо работает
Подтверждаю.
Получится лучшее их двух миров.
Может быть на C# с помощью ключ слова dynamic Тоже можно как-то изъябьнуца, но это не точно
я пирдумал, правдла для сисечки, а не для крестов (на кресты сам переведи).
Собираешь модули: petuh.dll(so), krestuh.dll(so) итд. В каждом делаешь функцию init().
Потом из строки строишь путь, загружаешь через LoadLibrary (dlopen), и передаешь управление в init.
Я плагины так делал как-то
Для дополнительного веселья надо забыть заэскейпить «..».
у фара наприме это так работает, и еще дофига где
нужен паттерн приспособленец!
Красивое решение это генерация такого кода из языка описаия проткоола
Я там выше ссылк дава на binpac
Кстати, машинисты метро иногда в шутку «Боингом» называют такой аппарат:
https://ru.wikipedia.org/wiki/81-717/714
Потому что 717.
Тогда
* в base можно добавить static base *pituxes[PITUXES]; static size_t pituxes_length = 0;
* в pituz<T> добавить статический pituz<T>::bagor, который делает
pituxes[pituxes_length++] = new T;
* в pituz<T> добавить виртуальную питушню pituz<T>::insert = \m -> m[тут взять имя класса у рттиуха] = this
* бормандов instances заполнять как map (flip insert m) pituxes.
То есть за счёт питушино-рекурсивного наследовательного паттерна прописать всем детям питушню для добавления себя в питухов на статическом этапе, а также - себя и своего имени в выбранную мапу, когда будет мапа. Когда статика отработает, и все питухи инициализируются, можно будет воспользоваться STL. В программе берём мапу и форычим питухов, прося их добавиться в мапу.
Тогда каждый новый питух должен только унаследоваться от pitux<новый питух>, и он ватоматически добавится куда надо.
Я всё равно не чувствую весомости потери гибкости. Получать классы по именам надо не в каждом проекте, а вот чтобы ещё несколько разных групп было - вообще редкий вариант.
Ну не знаю, можно тогда из pituxes нагенерировать новые питушни по вкусу.
Или сделать pituz<T, GROUP1 | GROUP3 | PITUXI> - какую-то битушню с группами, и автоматически распихивать по группам.
Хотя, я не знаю, зачем вообще весь этот пердолинг и какие подмножества питушни могут понадобиться.
> связный список
Как мне кажется, долговато кодить для статической питушни. да и массив - царская питушня.
Кстати, malloc может на этапе статический инициализации быть не готовым к работе?
Плюс с мапой чётко и в одном месте видно, что именно используется. И ты получишь ошибку конпеляции если что-то из этого забыл запилить.
>И ты получишь ошибку конпеляции если что-то из этого забыл запилить.
Если я забуду добавить в мапу, ошибки компиляции не будет. Хотя классы будут потомками Base и всё такое.
В случае с наследованием от вореционизатора я либо сразу не буду потомком Base, и компиляцию прикроют, либо буду и потомком, и сяду в мапу.
Да и про один файл - это миф. Один хер тест какой-нибудь добавлять.
На этом этапе проблема. В крестах статических блоков инициализации (как в ЙАЖА, например) нетути, можно только городить ненадёжную и нестабильную питушню вроде «static auto huj = static_initialization_function()», но так возникают проблемы от порядка инициализации (я вот хз, например, будет ли инициализирован CRT на момент вызова static_initialization_function()) и до множественной инициализации (если разместить функцию в .h).
* массив metuxes не указателей, а просто объектов (чтобы без malloc и прочей питушни)
* bagor с помощью placement new раскатывает в metuxes объект creator<T> с виртуальным методом который создаёт и помещает unique_ptr<T> в выбранную мапу.
Думаю, у всех креаторов будет размер как у указателя на vtable, поэтому их можно будет перебирать по значению и вытягивать из массива питухов реинтерпрет питухом.
pituxes станет char metuxes[100500] и вообще может стать статик питухом у base_creator, bagor будет делать
Главный вопрос в том, как он это будет делать. Нормальных статических блоков-то не завезли, поэтому нам придётся дёргать этот код в рантайме, а для этого надо, опять же, проитерироваться по всем зарегистрированным creator<T>.
Так и будет base <|--- pituz<S0> <|--- S0.
У pituz<S0> будет статический экземпляр pituz<S0>::creator_for_creator, у которого в конструкторе будет
creator<T> имеет виртуальный метод для создания T.
Хотя, давай по новой.
Вместо него можно использовать
Эта питушня будет создавать unique_ptr на новый объект и складывать его в мапу your_map.
metuxes создать как простой массив указателей на функции типа void (*)(std::map<..., uniq...<Base>>&);
У pituz<T> будет статический экземпляр pituz<T>::creator_for_creator, у которого в конструкторе будет metuxes[metuxes_lenth++] = put_me<T>;
А дальше будет функция fill_your_map, которая будет брать metuxes и вызывать их на переданной мапе в нужном месте.
При создании нового класса надо будет наследовать его от pituz<этот класс> и всё.
А там, где нужна мапа - делать std::map<.....> m; fill_your_map(m);
Вроде всё упавшее снова разложил по полочкам.
1. Статический член (в твоей нотации — creator_for_creator) не инициализируется, если к нему явно не обратиться.
2. Этот же самый код, собранный через «clang», падает с сегфолтом. «Gcc» и «MSVC» работают (но согласно первому пункту).
Собственно, как я и говорил в верхних комментах, статическая иницализация в крестах — говно ёбанное. То ли дело ЙАЖА.
Которая из её форм? Надо ещё парочку добавить чтобы пофиксить.
Что ебень, что не ебень
http://govnokod.ru/15263
Поэтому я предлагал изначально на всякий случай питушить в простой массив.
> что будет делать put_me()
Создавать объект и добавлять в бормандову мапу
> и как будет реализована createObject(string name)?
return instances.at(name);
где instances - бормандова питушня из второго комментария.
> А там, где нужна мапа - делать std::map<.....> m; fill_your_map(m);
std::map<.....> instances; fill_your_map(instances);
Дык в мапу надо добавлять не объект, а функцию, создающую объект.
> return instances.at(name);
Дык нужны не синглтоны, а обычные объекты.
> Есть опасение
Дык не опасение, а реальность — оно вообще нихрена не работает.
Тут предлагают вставить в BaseRegistrator<>
Если попердолить это выражение, компиляторы перестают выдавать предупреждение, а код всё ещё работает.
Перенёс пердолинг с STL и прочей питушнёю сложнее царского массива в main, как и планировал.
Правда, я что-то не то сделал, и код со string_view сломался - заменил на string.
Вот, в итоге заставил работать эту питушню:
https://wandbox.org/permlink/KBmYlLmfVWyInOxk
Из-за синглтонства пришлось unique_pitux заменить на shared_pitux, сделал поэтому вспомогательный pointer<T>
> надо добавлять не объект, а функцию, создающую объект.
Хорошо, не будем слушать восьмишка, это тоже можно: https://wandbox.org/permlink/WT9nQqCZJfBPhcIb
Со static_assert, впрочем, выглядит как крайне ненадёжный хак, который сломается в следующей мажорной версии. Именно поэтому я против «C++».
and then just map me
till I can fill your registration