- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
struct Base { virtual const char *getName() = 0; virtual ~Base() = default; };
struct SE_0 : Base { virtual const char *getName() override { return "SE_0"; } };
struct SE_1 : Base { virtual const char *getName() override { return "SE_1"; } };
struct SE_2 : Base { virtual const char *getName() override { return "SE_2"; } };
enum TypesEnum {
E__BEGIN = 0,
E_0 = E__BEGIN,
E_1,
E_2,
E__END
};
template<TypesEnum>
struct Registry {};
template<>
struct Registry<E_0> {
static constexpr const char *name = "The first type (SE_0)";
using type = SE_0;
};
template<>
struct Registry<E_1> {
static constexpr const char *name = "A second type (SE_1)";
using type = SE_1;
};
template<>
struct Registry<E_2> {
static constexpr const char *name = "And the last type (SE_2)";
using type = SE_2;
};
template<TypesEnum CurrentType>
std::unique_ptr<Base> createTypeImpl(const char *name)
{
if constexpr (CurrentType < E__END) {
if (strstr(Registry<CurrentType>::name, name)) {
return std::make_unique<typename Registry<CurrentType>::type>();
}
return createTypeImpl<static_cast<TypesEnum>(CurrentType + 1)>(name);
} else {
(void)name; // Silence 'unreferenced formal parameter' warning
return nullptr;
}
}
std::unique_ptr<Base> createType(const char *name)
{
return createTypeImpl<E__BEGIN>(name);
}
int main()
{
std::cout << "first type: " << createType("first type")->getName() << std::endl;
std::cout << "second type: " << createType("second type")->getName() << std::endl;
std::cout << "last type: " << createType("last type")->getName() << std::endl;
return EXIT_SUCCESS;
}
Упоролся.
https://ideone.com/c11fz4
Но в Ди с рефлексией проще. Тупо перечислил в цикле все имена в модуле, нашел потомков 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 просматривает пачку классов, проверяя вхождение строки в поле, и когда находит, возвращает другой связанный с ним класс?
Юзер вводит «first type» — создаётся объект типа «SE_0»; вводит «second type» — объект типа «SE_1» и так далее.
В скриптушне я бы просто сделал декоратор а-ля @register (выше пример), а вот с крестами проблемка выходит — сделать инициализацию рантайм-карты без явного перечисления типов и строк в createObjectByName() проблематично*.
*Можно, но заёбисто.
Самое страшное это писать одно и тоже знание в нескольких местах.
Потому в генерилке ты пишешь его ОДИН раз, а дальше оно само генерийет бойлерплейт где хоть 100500 раз это знание написино.
Когда я паршу текст -- я описываю грамматиики и потом лексы с бизонами за меня генерят код с говном
Ты пишешь парсер сетевого протокола. Это тоже самое.
Тебе нужно описание этого протокола в каком-то формате, где к каждому типу пакета привязан класс.
И геренилка кода, которая эту хуйню за тебя сгенерит.
ЗЫ: Я нагуглилъ
http://www.icsi.berkeley.edu/pubs/networking/binpacIMC06.pdf
https://github.com/zeek/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