Кресты / Говнокод #26621 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 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

Запостил: gost gost, (Updated )

Комментарии (109) RSS

  • Когда захотел запилить рантайм-фабрику, а вменяемых метатипов не завезли.
    Ответить
  • Блин, я что-то как тот чел из хабростатьи. Смотрю на этот код, вижу треугольные скобочки, и не могу его читать.
    Ответить
    • Так ведь очевидно же все.
      Но в Ди с рефлексией проще. Тупо перечислил в цикле все имена в модуле, нашел потомков Base и создал.
      Ответить
          • Нидлесс тихо-мирно засыпал за щеку, но почему-то решил открыть говнокодик и теперь он пытается прочитать какое-то крестоговно.

            Проклинаю васю
            Ответить
        • Х.з. как в J, но в форте можно просто сходить да почитать словарь.
          Ответить
        • Хренево, объекты и классы в J то же, что и локали (неймспейцы по вашему, но их можно создавать в рантайме). Через жопу 4!:1 (описани https://www.jsoftware.com/docs/help807/dictionary/dx004.htm) можно получить имена в текущей локали (например 4!:1]0 получит имена существительных), но перечисляются только имена только в текущей локали, из локали которой наследуемся получить не могем, и имена родительской или унаследованной локали также получить не могем. Хоть имена локалей тем же способом (4!:1]6) и можно получить, но у них отдельный и единый неёмспейс и в списке приходят имена сразу всех имеющихся локалей. Единственное что нарыл (ну натыкал в jcоcноле): при создании объекта у него создаётся поле COCREATOR, в котором хранится имя локали в котором его создали.

          Но для того, чтобы в рантайме выбрать класс это и не нужно.
          Ответить
      • Да код несложный, просто я вижу треугольные скобочки и желание читать отпадает.
        Ответить
          • a<b, c> d;

            З.Ы. Где-то у меня был пример, который в зависимости от значения константы компилится либо как шаблон либо как операторы сравнения.
            Ответить
            • https://medium.com/@mujjingun_23509/full-proof-that-c-grammar-is-undecidable-34e22dd8b664

              > 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++ надо решить проблему остановки. Какой багор )))
              Ответить
            • А есть пример, где в зависимости от константы что-то компилируется к как ключевое слово или имя символа?
              Ответить
              • Маловероятно. Можно попробовать что-то подобрать с контекстно-зависимыми ключевыми словами типа override, но лень. С остальными точно не прокатит.
                Ответить
            • Надо было им новые скобочки изобрести, а не использовать хуйню "больше-меньше". Например, через комбинацию обычных скобочек с какой-нибудь хуйней, которая не встречается. Типа @%$( как открывающая и )@%$ как закрывающая. Можно даже вводить сколько угодно видов скобочек, типа вот такого пизданатства
              @0%$( какая-то-хуйня )@0%$
              @1%$( какая-то-хуйня )@1%$
              @2%$( какая-то-хуйня )@2%$
              @3%$( какая-то-хуйня )@3%$

              и так далее. Наверняка в каком-нибудь стандарте появится и такая поебень
              Ответить
              • Да лучше уж「какие-нибудь юникодные」чем эти триграфы.
                Ответить
                • Тогда для их ввода надо будет какие-то хоткеи придумывать, или специальную раскладку. Да и юникод может закончиться. Еще б сделать, чтобы скобочки перегружать можно было и определять как некие новые как бы операторы, и чтоб с неймспейсами. Например, на какой-нибудь метушне можно описать что у нас теперь есть скобочки типа @0%$( и )@0%$ которые такую-то хуйню делают, и можно или делать my_namespace::@0%$( некаяхуйня my_namespace::)@0%$
                  или сделать using namespace my_namespace; и тогда просто@0%$( некаяхуйня )@0%$ писать можно. Это ж какой простор для творчества!
                  Ответить
                  • Кстати, почему в крестах сделали хуйню с using, но не сделали хуйни, чтоб этот using где-нибудь отменить? Типа
                    using namespace std;
                    
                    cout << "test\n"; // work
                    
                    unusing namespace std;
                    
                    cout << "test\n"; // doesnt work


                    Да, я знаю что можно в пределах какой-то одной функции/метода и пр. эту хуйню с юзингом сделать, но это не то.
                    Ответить
                    • Потому что кресты и так хуёво читаются, а тут ещё искать в середине файла эти using'и... Сейчас в адекватных случаях они всё-таки стоят или прям сверху файла или в начале скоупа.
                      Ответить
                    • using std = delete;

                      Во! Я думаю теперь точно примут пропозал.

                      Ну и using std = default на случай если ты затёр std чем-то другим и теперь хочешь вернуть на место.
                      Ответить
                      • > Ну и using std = default на случай если ты затёр std чем-то другим и хочешь вернуть на место.

                        Лучше сделать pop(n). Типа, если несколько раз перезатер, можно на столько-то раз откатиться.

                        using std = pop(2);
                        Ответить
                        • Да и вообще, стек это говно для анскиллябр, ведь настоящие Цари знают, что единственная полезная структура данных - массив. Надо делать тьюринг-полный язык для манипуляций с массивом неймспейсов, а не просто какой-то там pop и delete.

                          Это вообще суть крестов, взять какую-нибудь тупую херню типа шаблонов, и раздуть ее до уровня маразма
                          Ответить
                          • compiletime {
                                auto backups = std::deque<std::any>();
                            
                                backups.push_front(std);
                                backups.push_front(delete);
                            
                                std = nullptr;
                                delete = nullptr;
                            }
                            
                            // ... work without std and delete
                            
                            compiletime {
                                delete = backups.front();
                                backups.pop_front();
                                std = backups.front();
                                backups.pop_front();
                            }
                            Ответить
                        • Помнится, я такую питушню для переменных писал: https://github.com/1024--/peetooshnya/tree/master/varprepr
                          С этим препроцессором можно переиспользовать имена переменных, создавая микроскоупы. Там есть реализации для кода на C, Python или JS, можно добаалять свои.
                          Ответить
                      • Надо ещё придумать, как переиспользовать старые ключевые слова вроде static, const.
                        Ответить
            • > в зависимости от значения константы компилится либо как шаблон либо как операторы сравнения.

              https://govnokod.ru/26283#comment518451
              > Еще выяснилось, что я не итератор, а шаблон. Ну и черт с ним, подумал я.
              Ответить
  • А сбалансированное дерево вместо линейного поиска слабо запилить?
    Ответить
  • Что делает этот код?

    Поправь меня, если чио: createTypeImpl просматривает пачку классов, проверяя вхождение строки в поле, и когда находит, возвращает другой связанный с ним класс?
    Ответить
    • А, моя понял, в рантайме выбираеца класс и создаётся объект.
      Ответить
      • Да. В каком-нибудь я бы просто сделал что-нибудь вроде
        REGISTRY = {'first type': SE_0, 'second type': SE_1, 'last type': SE_2}
        obj = REGISTRY[name]()
        , а в кресты рантайм-метатипов не подвезли
        Ответить
        • А в каком компилируемом мейнстрим языке это можно сделать?
          В жабах с шарпеями же только рефлексией. В скриптогавне то в любом можно
          Ответить
          • Ну вот ЙАЖА, например. Там, ЕМНИП, можно на аннотациях такое нахуевертить. Что-то вроде (псевдо-ЙАЖА)
            @register("first type")
            class SE_0 {...}
            
            @register("second type")
            class SE_1 {...}
            
            ...
            Ответить
            • Все равно будет рефлекися же (ну или патчинг класс файлов).

              В йпже можно найти классы по аннотации, но инстанциировать их все равно будет рефлексия
              Ответить
                • Рефлексия считается не очень красивым решением: она не очень быстрая, и может быть не очень безопасная. Так что использовать ее лучше для инфраструктурного кода только.

                  Например, ты можешь взять Spring (или другой контейнер) и там будет такой API.
                  Но если ты встроишь рефлексию посреди бизнес-логики, то на тебя посмотрят косо.
                  Ответить
                  • Ну в общем-то да, согласен, городить такие велосипеды чисто на java.lang.reflect.* действительно не стоит.
                    Ответить
                    • Если все классы одинаковые, то можно взять enum: он умеет найти по имени.

                      Вроде скоро в джаву завезут умные енумы, которые могут быть разными классами, тогда станет прочще
                      Ответить
        • Я вообще не понял что нужно сделать.
          Ответить
          • Создать объект, класс которого определяется строкой в рантайме.
            Юзер вводит «first type» — создаётся объект типа «SE_0»; вводит «second type» — объект типа «SE_1» и так далее.
            Ответить
            • Что такое «Объект типа SE_0»? Приведи реальный пример что нужно, без реализации.
              Ответить
              • Реальный пример: есть N типов пакетов (сетевых), различающихся по заголовку (строка в начале). Для каждого пришедшего из сети пакета нужно создать соответствующий объект, передав в его коньструктор данные из пакета. Ситуация усугубляется тем, что заголовок отделяется от данных разными символами: где-то пробелом, где-то новой строкой, а в одном пакете — вообще обратным слэшем. Для дополнительного веселья в некоторых видах пакетов данных может вообще не быть (просто строка заголовка), а для некоторых — может быть, а может и не быть.
                Ответить
                • я бы сделал массив читтателей.
                  Каждый читатель читал бы заголовок и говорил бы "О! Мой пездюк! Вот тебе для него абект"
                  или
                  "Первый раз вижу, вот тебе null".

                  Итерировался бы до первого ненулевого значения.

                  Бойлерплейт в читателях уменьшил бы посредством шаблонов
                  Ответить
                • То есть тебе нужно что-то типа
                  class Package;
                  class PackagePituh : Package;
                  class PackageKuritsa : Package;
                  map<string, Constructor> karta;
                  karta["x1"] = PackagePituh;
                  karta["x2"] = PackageKuritsa;
                  new karta(header)(header, content);


                  ?
                  Ответить
                  • Да, что-то вроде этого, только вместо простого соответствия x1 -> Pituh, x2 -> Kuritsa там накостылить костылей нужно.
                    Ответить
                    • а нельзя сделать мапку строка--указатель-на-функцию-фабрику ?
                      ну потом ее вызываешь, и она создает тебе нудный класс?
                      Ответить
                      • Можно, но тогда возникает проблема с засовыванием в эту карту значений (это нужно сделать для каждого класса, и желательно с как можно меньшим бойлерплейтом).
                        В скриптушне я бы просто сделал декоратор а-ля @register (выше пример), а вот с крестами проблемка выходит — сделать инициализацию рантайм-карты без явного перечисления типов и строк в createObjectByName() проблематично*.

                        *Можно, но заёбисто.
                        Ответить
                        • Наскока я понимаю в сишечке (и вероятно в кристах) подход должен быть такой: если ты не хочешь писать бойлерплейт руками, и не можешь (или не хочешь по причинам перформансе) заставить рантайм сделать это за тебя, то ты используешь генерилку кода.

                          Самое страшное это писать одно и тоже знание в нескольких местах.
                          Потому в генерилке ты пишешь его ОДИН раз, а дальше оно само генерийет бойлерплейт где хоть 100500 раз это знание написино.

                          Когда я паршу текст -- я описываю грамматиики и потом лексы с бизонами за меня генерят код с говном

                          Ты пишешь парсер сетевого протокола. Это тоже самое.
                          Тебе нужно описание этого протокола в каком-то формате, где к каждому типу пакета привязан класс.

                          И геренилка кода, которая эту хуйню за тебя сгенерит.


                          ЗЫ: Я нагуглилъ
                          http://www.icsi.berkeley.edu/pubs/networking/binpacIMC06.pdf
                          https://github.com/zeek/binpac
                          Ответить
                          • Да я уже нахуевертил эту генерилку на шоблонах (по типу того, что в посте) и мокросах (намокросил табличку соответствия пакетов, в сущности, это и есть то самое описание), благо что там всего двенадцать типов пакетов есть.
                            Ответить
                            • ну как знаешь, но я бы взглянул на /binpac
                              беркли хуйни не посоветует
                              Ответить
                      • +

                        Как бы то ни было, шоблонное говно я буду юзать в последнюю очередь.
                        Ответить
            • Сделай свой DSL с помощью Spirit, и опиши в нем это знание
              А из DSLя автоматически нагенери пачку switch/if.

              Нативно такие штуки хорошо писать толко на скриптоговне: там это вообще всегда их коробки и хорошо работает
              Ответить
              • Ой, нет, я ещё не настолько ёбнулся. Лучше уж на велосипеде покататься, благо проект личный.

                > Нативно такие штуки хорошо писать толко на скриптоговне: там это вообще всегда их коробки и хорошо работает
                Подтверждаю.
                Ответить
                • Под JVM ты можешь конгкретно это написать на груви: там это легко. А все остальное на джаве.

                  Получится лучшее их двух миров.
                  Может быть на C# с помощью ключ слова dynamic Тоже можно как-то изъябьнуца, но это не точно
                  Ответить
            • о
              я пирдумал, правдла для сисечки, а не для крестов (на кресты сам переведи).

              Собираешь модули: petuh.dll(so), krestuh.dll(so) итд. В каждом делаешь функцию init().
              Потом из строки строишь путь, загружаешь через LoadLibrary (dlopen), и передаешь управление в init.

              Я плагины так делал как-то
              Ответить
              • Хардкорно!
                Для дополнительного веселья надо забыть заэскейпить «..».
                Ответить
                • и случайно загрузить в адресное пространство немного говна, да
                  Ответить
              • А я тупо грузил всё подряд из каталога с плагинами и звал у них init(). Внутри которого они уже регались в нужных мапах.
                Ответить
                • да тащимто это стандартный способ загрузки плагинов, да
                  у фара наприме это так работает, и еще дофига где
                  Ответить
  • std::map<std::string, std::function<std::unique_ptr<base> ()>> factory = {
        { "S0", [](){ return std::make_unique<S0>();} }
        { "S1", [](){ return std::make_unique<S1>();} }
        { "S2", [](){ return std::make_unique<S2>();} }
    };
    
    factory.at(name)();
    Впизду шаблоны.
    Ответить
    • на каждый хрюк инстанцииовать новый объект?

      нужен паттерн приспособленец!
      Ответить
      • std::map<std::string, std::unique_ptr<base>> instances = {
            { "S0", std::make_unique<S0>(); },
            { "S1", std::make_unique<S1>(); },
            { "S2", std::make_unique<S2>(); },
        };
        
        instances.at(name);
        Впизду паттерны.
        Ответить
        • ну вот и начался бройлер плейт: надо на каждый S1 по одной хуйне добавлять и туда и сюда

          Красивое решение это генерация такого кода из языка описаия проткоола
          Я там выше ссылк дава на binpac
          Ответить
                • В старых заставках показывали «А320», хотя голос диктора говорил про «Бройлер-747». Потом видеозапись «А320» поменяли на компьютерную графику самолёта с надписью «Бройлер-747». Вроде даже старые серии перемонтировали.

                  Кстати, машинисты метро иногда в шутку «Боингом» называют такой аппарат:
                  https://ru.wikipedia.org/wiki/81-717/714

                  Потому что 717.
                  Ответить
          • А если сделать иерархию 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 может на этапе статический инициализации быть не готовым к работе?
                Ответить
                • Вот именно! Зачем вообще весь этот пердолинг если вручную описанная мапа проста, понятна и не нарушает SRP.

                  Плюс с мапой чётко и в одном месте видно, что именно используется. И ты получишь ошибку конпеляции если что-то из этого забыл запилить.
                  Ответить
                  • Да, но

                    >И ты получишь ошибку конпеляции если что-то из этого забыл запилить.
                    Если я забуду добавить в мапу, ошибки компиляции не будет. Хотя классы будут потомками 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> в выбранную мапу.

                base_creator <|--- creator<T>
                
                struct base_creator {
                  virtual void insert(std::map<...>) = 0;
                };
                
                template <typename T>
                struct creator {
                 void insert(... m) {
                    m[RTTIухname] = std::make_unique<T>();
                 }
                };


                Думаю, у всех креаторов будет размер как у указателя на vtable, поэтому их можно будет перебирать по значению и вытягивать из массива питухов реинтерпрет питухом.
                Ответить
                • Тогда иерархия самих классов останется как base <|-- S0, классы не будут ничем зашкварены.

                  pituxes станет char metuxes[100500] и вообще может стать статик питухом у base_creator, bagor будет делать
                  new (reinterpret_cast<creator<T>*>(metuxes) + metuxes_count++) creator<T>;
                  Ответить
                  • > bagor будет делать
                    Главный вопрос в том, как он это будет делать. Нормальных статических блоков-то не завезли, поэтому нам придётся дёргать этот код в рантайме, а для этого надо, опять же, проитерироваться по всем зарегистрированным creator<T>.
                    Ответить
                    • Багор будет делать где-нибудь в статушне, да. Я наврал про то, что base <|-- S0 и запутался.

                      Так и будет base <|--- pituz<S0> <|--- S0.

                      У pituz<S0> будет статический экземпляр pituz<S0>::creator_for_creator, у которого в конструкторе будет
                      new (reinterpret_cast<creator<T>*>(metuxes) + metuxes_count++) creator<T>;

                      creator<T> имеет виртуальный метод для создания T.


                      Хотя, давай по новой.
                      Вместо него можно использовать
                      template <typename T> void put_me(std::map<..., uniq...<Base>>& your_map);

                      Эта питушня будет создавать 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);

                      Вроде всё упавшее снова разложил по полочкам.
                      Ответить
                      • А какая была бизнес-задача? И была ли? Может это случай XY проблемы? По-любому надо было для 5 классов решить.
                        Ответить
                      • Ничего не понял, что будет делать put_me() и как будет реализована createObject(string name)?
                        Ответить
                      • Нахуевертил поебень по мотивам, которая должна регистрировать тип, отнаследованный от BaseRegistrator<T> (какой «CRTP», кстати!): https://wandbox.org/permlink/0RWVZIDjQTYNjbvU. Есть две проблемы:
                        1. Статический член (в твоей нотации — creator_for_creator) не инициализируется, если к нему явно не обратиться.
                        2. Этот же самый код, собранный через «clang», падает с сегфолтом. «Gcc» и «MSVC» работают (но согласно первому пункту).

                        Собственно, как я и говорил в верхних комментах, статическая иницализация в крестах — говно ёбанное. То ли дело ЙАЖА.
                        Ответить
                        • > статическая инициализация - говно ебаное

                          Которая из её форм? Надо ещё парочку добавить чтобы пофиксить.
                          Ответить
                        • Если в башне поебень,
                          Что ебень, что не ебень
                          Ответить
                        • Есть опасение, что ДОБРОЕ ОПРЕДЕЛЕНИЕ ДОБРАЯ ПЕРЕМЕННАЯ ИДЕНТИФИКАТОР ИДЕНТИФИКАТОРЕК В ЧЕСТИ Главная карта может как-то плохо себя вести. У меня был пост про выстрел в ногу со статушнёй:
                          http://govnokod.ru/15263

                          Поэтому я предлагал изначально на всякий случай питушить в простой массив.

                          > что будет делать put_me()
                          Создавать объект и добавлять в бормандову мапу
                          template <T>
                          void put_me(std::map<std::string, std::unique_ptr<T>>& m) {
                            m[T::name()] = std::make_unique<T>();
                          }


                          > и как будет реализована 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);
                            Дык нужны не синглтоны, а обычные объекты.

                            > Есть опасение
                            Дык не опасение, а реальность — оно вообще нихрена не работает.
                            Ответить
                            • https://stackoverflow.com/questions/6420985/how-to-force-a-static-member-to-be-initialized
                              Тут предлагают вставить в BaseRegistrator<>
                              static_assert(&creator);

                              Если попердолить это выражение, компиляторы перестают выдавать предупреждение, а код всё ещё работает.

                              Перенёс пердолинг с STL и прочей питушнёю сложнее царского массива в main, как и планировал.
                              Правда, я что-то не то сделал, и код со string_view сломался - заменил на string.

                              Вот, в итоге заставил работать эту питушню:
                              https://wandbox.org/permlink/KBmYlLmfVWyInOxk
                              Из-за синглтонства пришлось unique_pitux заменить на shared_pitux, сделал поэтому вспомогательный pointer<T>

                              > надо добавлять не объект, а функцию, создающую объект.
                              Хорошо, не будем слушать восьмишка, это тоже можно: https://wandbox.org/permlink/WT9nQqCZJfBPhcIb
                              Ответить
                              • Годно!

                                Со static_assert, впрочем, выглядит как крайне ненадёжный хак, который сломается в следующей мажорной версии. Именно поэтому я против «C++».
                                Ответить

Добавить комментарий

Семь раз отмерь — один отрежь, guest!

    А не использовать ли нам bbcode?


    8