1. C++ / Говнокод #20390

    +2

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    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
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    91. 91
    92. 92
    93. 93
    94. 94
    95. 95
    96. 96
    97. 97
    98. 98
    99. 99
    #define CREATE_EVENT_LISTENER(_elname, arg1_type, arg1_name) \
    class _elname : public EventListener	 \
    {	 \
    private:	 \
    	class IContainer	 \
    		{	 \
    	public:	 \
    		virtual void Call(arg1_type arg1_name) = 0;	 \
    		virtual ~IContainer() {}	 \
    		};	 \
    	 \
    	class FunctionContainer : public IContainer	 \
    		{	 \
    	private:	 \
    		typedef void(*__CallbackPtr)(arg1_type);	 \
    	public:	 \
    		FunctionContainer(__CallbackPtr fn)	 \
    				{	 \
    			this->fn = fn;	 \
    				}	 \
    	 \
    		virtual void Call(arg1_type arg1_name)	 \
    				{	 \
    			fn(arg1_name);	 \
    				}	 \
    	 \
    	private:	 \
    		__CallbackPtr fn;	 \
    		};	 \
    		 \
    	template<class T, class Q>	 \
    	class MethodContainer : public IContainer	 \
    		{	 \
    	public:	 \
    		MethodContainer(T method, Q _this)	 \
    				{	 \
    			this->method = method;	 \
    			this->_this = _this;	 \
    				}	 \
    	 \
    		virtual void Call(arg1_type arg1_name )	 \
    				{	 \
    			(_this->*method)(arg1_name);	 \
    				}	 \
    	 \
    	private:	 \
    		T method;	 \
    		Q _this;	 \
    		};	 \
    public:	 \
    	typedef void(*__FN_CALLBACK)(arg1_type);	 \
    	 \
    	_elname(__FN_CALLBACK fn)	 \
    		{	 \
    		this->container = new FunctionContainer(fn);	 \
    		}	 \
    	 \
    	template <class T, class Q>	 \
    	_elname(T method, Q _this)	 \
    		{	 \
    		this->container = new MethodContainer<T, Q>(method, _this);	 \
    		}	 \
    	 \
    	void Call(arg1_type arg1_name)	 \
    		{	 \
    		container->Call(arg1_name);	 \
    		}	 \
    	 \
    	virtual ~_elname()	 \
    		{	 \
    		delete this->container;	 \
    		}	 \
    private:	 \
    	IContainer* container;	 \
    };	 \
    
    #define CREATE_EVENT(_ename, _elname, arg1_type, arg1_name) \
    class _ename : public Event	 \
    {	 \
    public:	 \
    	void AddListener(_elname* listener)	 \
    		{	 \
    		Event::AddListener(listener);	 \
    		}	 \
    	 \
    	void Handle(arg1_type arg1_name)	 \
    		{	 \
    		for (size_t i = 0; i < this->listeners.size(); i++)	 \
    												{	 \
    			((_elname*)listeners[i])->Call(arg1_name);	 \
    												}	 \
    		}	 \
    	 \
    	void RemoveListener(_elname* listener)	 \
    		{	 \
    		Event::RemoveListener(listener);	 \
    		}	 \
    	 \
    };	 \

    Я когда то это написал. Думал, это хорошая идея...
    Полный файл: https://github.com/arhyme/CPP_EVENTS/blob/master/Event.h

    Запостил: Avery, 18 Июля 2016

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

    • хоть бы выровнял \
      Ответить
    • ПОСОНЫ, НЕ ОТКРЫВАЙТЕ ЭТОТ ГОВНОКОД, ВЕСЬ МОНИТОР В ЧЁРТОЧКАХ, ПИШУ С ТАПКА!
      Ответить
    • В очередной раз подтверждено, что табы - пидорская тема.
      Это такая обфускация?
      for (size_t i = 0; i < this->listeners.size(); i++)	 \
      												{	 \
      			((_elname*)listeners[i])->Call(arg1_name);	 \
      												}	 \
      Ответить
      • едва ли дело именно в табах, если скобки дальше их содержимого уплывают
        Ответить
      • В ИДЕ говнокодера всё работает.
        Ответить
      • > В очередной раз подтверждено, что табы - пидорская тема.

        не гони на табы.

        они не виноваты в том что некоторые идиоты (ака: подавляющее большинство девелоперов) до 8 считать не умеют.

        ЗЫ копи-пасти в VIM. потом ":set ts=4"
        Ответить
    • Дождик код намочил
      Ответить
    • Прямо из СТАНДАРТА:

      (3.1) Each identifier that contains a double underscore __ or begins with an underscore followed by an
      uppercase letter is reserved to the implementation for any use.
      (3.2) Each identifier that begins with an underscore is reserved to the implementation for use as a name in
      the global namespace

      Good job, fag.
      Ответить
      • компилятор сожрал значит можно!
        Ответить
        • Сожрал и сгенерил system("rm -rf /"); ибо нехуй тут UB писать.
          Ответить
          • так если будет конфликт имен вылетит нарушение ODR
            Ответить
            • Если конфликтующие функции — inline, то не вылетит, а будет с троллфейсом херить логику программы.
              Ответить
              • так даже одноименные инлайн функции не разрешены в одном tu
                Ответить
                • А если они окажутся в разных:

                  Функция А имеет два разных определения в разных TU: А1 и А2.

                  А1 заинлайнилась в месте использования, а А2 компилер решил не инлайнить.

                  Линкер увидел что А — inline и взял первое попавшееся определение — А1.

                  Теперь код, который хотел вызвать А2 вызывает А1. И заметить это непросто.
                  Ответить
                  • если я не совсем дурак, то inline функции не должны даже доходить до этапа линковки. И А2 вместо А1 не вызовется.

                    (потестил на mingw. inline-определение перекрыло не инлайн-объявление, что по идее странно, но в остальном сработало предсказуемо)
                    Ответить
                    • Объявление inline всего лишь разрешает объявлять функцию несколько раз. Решение инлайнить или нет — за компилятором. Если он решит не инлайнить — будет сгенерировано нормальная функция, которую потом вызовут. Более того, если возьмут адрес инлайн функци, то компилеру придётся сгенерировать тело, т.к. неизвестно кто будет её потом вызывать. Линкеру потом передаётся информация что эта функция — inline и на лишние копии не надо ругаться, а выбрать одну из них.
                      Ответить
                    • > если я не совсем дурак, то inline функции не должны даже доходить до этапа линковки.

                      статик инлайн.

                      обычные инлайн функции они просто обычные функции (с хинтом компилеру "плиз заинлайнь"), и если у тебя есть два определения в разных TU, то линкер пожалуется.
                      Ответить
                      • а если __forceinline? (или подобное)
                        Ответить
                        • Это уже компилятороспецифичные фичи. Если разрешат взять адрес такой функции, то генерировать определение всё равно придётся.
                          Ответить
                        • always_inline не меняет глобальной видимости функции, и компилер так или иначе сгенерит инстанцию функции.

                          https://gcc.gnu.org/onlinedocs/gcc/Inline.html

                          PS из доки, единственная разница между inline vs always_inline это что последнее даже в дебуге будет заинлайнено.
                          Ответить
    • > когда-то
      > 8 апреля

      Только не говори, что с тех пор ты повзрослел, набрался опыта, все переосмыслил и сейчас бы уже такое не сделал.
      Ответить
      • дата когда код был залит на гитхаб, не обязятельно соответствует дате когда код писался.
        Ответить
    • private: typedef void (X*)();
      public: Y(X x){}

      Это нормально? Т.е. такой объект можно будет как-то создать снаружи?
      Ответить
      • Да. Y принимает объект типа указатель на функцию ничего не принимающую и не возвращающую. Алиас создан только для удобства классописателя.
        Ответить
        • Тоесть в С++ утиная типизация?
          Ответить
          • Нет, это алиасы типов — просто имена для программиста, не изменяющие реальный тип.

            using my_int = int;
            assert(is_same<my_int, int>); //Всегда true, в любую функцию ждущую my_int можно засунуть int

            Утиная типизация — в шаблонах.
            Ответить
            • Какой-то странный подход. Мне как бы не жалко, но это ж значит, что:
              typedef seconds int;
              typedef minutes int;

              Может немножко крови попортить. Я думал, что только в сишке так.
              Ответить
              • С++ сохраняет обратную совместимость с С. поэтому.

                с другой стороны, для того что бы твой пример работал, придется долго потрахатся, потому что как никрути, как долго секунды/минуты конвертятся в инты/из интов, строгой типизации у тебя ни как не получится. я в прошлом подобное делал с enum'ами и знакомые делали со структурами/классами - те же яйца: надо часто конвертить туда сюда, потому что иначе арифметика не работает. а потом появляются еще и ошибки типа `seconds_t S = 42; minutes_t M = minutes_t(to_int(S) + 1);` и начинают опускаться руки, потому что понимаешь что как ни крути, от ошибок не спасешься. (и даже в какой-то степени хуже получается, потому что меньше ожидаешь ошибок в таких местах, т.к. типа type-safe обертками пользуешься.)
                Ответить
                • > minutes_t M = minutes_t(to_int(S) + 1)
                  Дык назови этот метод не to_int() а to_int_in_seconds() или seconds_as_int(). И говно сразу всплывёт на поверхность. Один хуй он нужен чуть менее чем никогда, поди только в реально низкоуровневых методах, поэтому длинное название никому не повредит...

                  З.Ы. А у нас вот тайпсейф обёртки неплохо код почистили от странных кастов, умножений и делений... И от раздумий "а в чём же эта хуйня измеряется", заодно.

                  > seconds_t S = 42
                  g:explicit
                  Ответить
                  • я не спорю что помогают (почему с древних времен такое и пишу).

                    я просто хотел подчеркнуть что это не панацея.

                    абсолютные обёртки - (seconds_as_int() - мама, роди меня назад) - жутко не удобно использовать (сам не писал, но arbitrary precision кода в жабе насмотрелся). и чем дырявее/удобнее обертка, тем меньше гарантий она предоставляет.
                    Ответить
                    • > жутко не удобно использовать
                      Ты так часто скармливаешь кишки этих обёрток системным апишкам и сторонним либам? Ну вот в этих местах это будет отличным напоминанием о том, в чём измеряется их параметр.

                      А explicit конструктор - это страховка от злоебучих SetTimer(event, TimerRelative, 380), в которых потом хуй поймёшь, то ли автор реально хотел 38 микросекунд, то ли всё-таки 380, но забыл про особенность ёбаного EFI'шного таймера, и надо перелопатить кучу спецификаций, чтобы выяснить сколько там реально должно стоять...
                      Ответить
                    • Ненавижу лютой ненавистью херню вроде
                      sleep(int timeout)

                      Ладно в сишке средств минимум, но уж в плюсцах-то всё есть, чтобы сделать нормально.

                      У нас в кодбазе повсюду std::chrono::{seconds,milliseconds}, полёт нормальный, касты в инт ни разу не видел.
                      // минутка саморекламы
                      https://habrahabr.ru/post/198568/
                      Ответить
                      • В С++17 с автогенерирующимися операторами сравнения количество бойлерплейта заметно уменьшится.
                        Ответить
                        • Они лексикографически сравнивают по всем полям? Или только == и != генерится, а > и < - как и раньше вручную?

                          Лень гуглить, пора няшек смотреть и спать...
                          Ответить
                      • > Ненавижу лютой ненавистью херню вроде
                        http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES#SetTimer.28.29

                        Тогда, я думаю, тебе понравится вот эта функция :3
                        Ответить
                        • > Тогда, я думаю, тебе понравится вот эта функция :3

                          Да, тут ещё лучше. И из сигнатуры сходу не понятно, спим for или until, и единицы измерения кучерявые.
                          Ответить
                      • > Ладно в сишке средств минимум, но уж в плюсцах-то всё есть, чтобы сделать нормально.

                        > // минутка саморекламы
                        > https://habrahabr.ru/post/198568/

                        да делали мы уже все это - уже 15 лет назад.

                        в прошлом (сечас не пробовал) грабли были что эти прокладки добавляли код. по старой памяти, тестовый код без прокладки был на ~10% меньше чем код с прокладкой.
                        Ответить
                        • > эти прокладки добавляли код
                          Ты про бинарный? Ну в дебаге прилично дуют, да, в основном из-за всяких ассёртов внутри операторов...
                          Ответить
                          • да - в релиз коде. по этой причине фишки с аксессором `var.value()` не катили: нельзя было сделать эти обёртки только для дебага/теста, потому что в релизе надо делать typedef у которого нет .value() метода.

                            за годы много чего поменялось - может нынешнии компилеры умнее при выкидывании лишнего кода.
                            Ответить
                            • > фишки с аксессором `var.value()` не катили
                              Ну акцессоры и конструкторы же в хедере были описаны, я надеюсь? Х.з., у меня сейчас всё выкидывает ;)
                              Ответить
                          • к слову. только что романову типо-безопастную прокладку с GCC 4.8 протестировал.

                            с прокладкой, или без прокладки (typedef int), GCC 4.8.2 генерит идентичный код, почти байт в байт.

                            так что можно пользоватся не напрягаясь.
                            Ответить
                            • Учитывая, что с шаблонами все проблемы решаются в стиле "ещё один уровень абстракции", "рекурсивное раскрытие типов", "добавить типы-теги", "добавим функцию, чтобы заработал вывод типов"; то разработчикам компиляторов ОЧЕНЬ важно чтобы подобные прокладки не влияли на производительность.
                              Ответить
                              • Но рано или поздно у компилятора сдают нервы, и он оставляет шаблон недораскрытым...
                                Ответить
                      • > https://habrahabr.ru/post/198568/

                        к слову. я пропустил что твой IdOf другим целям служит.

                        почти с тем же эффектом, вместо `template <> class IdOf {}` я в прошлом пользовался enum'ами: С++ разные энумы сравнивать/присваивать не даёт. другими словами, вместо `typedef IdOf<Gadget> GadgetId;` я делал просто `enum GadgetId {}`. (потестировал: на сравнение разных энумов, g++ бросает ворнинг, а не ошибку.)

                        основное отличие в том что энумы в числа конвертируются без вопросов - без класса прокладки этого не запретить.
                        Ответить
                        • > основное отличие в том что энумы в числа конвертируются без вопросов - без класса прокладки этого не запретить.

                          В старых плюсах нельзя выбрать underlying type у енума. Так что нужно как минимум ещё воткнуть в енум большую константу, чтобы компилятор взял достаточно широкий тип.

                          Кстати, там в комментах предлагали решение с enum class-ами, весьма годное, если юзать C++11.
                          Ответить
                          • > Кстати, там в комментах предлагали решение с enum class-ами, весьма годное, если юзать C++11.

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

                            ЗЫ но все равно пидары: не добавили строковое представления для членов энумов...
                            Ответить
                          • > компилятор взял достаточно широкий тип
                            А каст числа в енум случаем не UB, если в енуме не было такого числа?
                            Ответить
                          • 7.2.10. Enumeration declarations

                            An expression of arithmetic or enumeration type can be converted to an enumeration type explicitly. The value is unchanged if it is in the range of enumeration values of the enumeration type; otherwise the resulting enumeration value is unspecified.

                            З.Ы. А, in range, т.е. походу от минимального до максимального... Т.е. всё ок, если добавить в енум 0 и максимум.
                            Ответить
                  • >> Один хуй он нужен чуть менее чем никогда

                    Это Тор нужен чуть менее, чем никогда, а я нужен! У него молоко на губах не обсохло!
                    Ответить
                • Посмотри на std::ratio и на std::duration. Зачем писать функции для конвертации, если можно припахать компилятор?
                  Ответить
                  • А, ещё boost::units есть.
                    Ответить
                    • да, видел. только уже очень много лет как поздно. можно и самому было это в прошлом написать - только на кой хер?

                      в том же примере что с минутами/секундами - делашь нормальных человеческий `struct myTime { int hours, mins, secs; /* + overloaded ops */ }` и все опять же работает. во многих случаях нежелание делать специализированые типы (и желание что то генерик/юниверсал сделать) и ведет к говнокодам.
                      Ответить
                      • ... а в других к говнокодам ведет пренебрежение чем-то генерик/юниверсал. У нас в конторе тонна софта работает с комплексным исчислением. Не самопальных реализаций я еще не видел, хотя стандартное представление есть даже в C99
                        Ответить
                        • apples vs oranges. "тонна софта работает с комплексным исчислением" это не то же самое что в нескольких местах работать с датами. с другой стороны, операции над комплексными числами хорошо определены и про них даже в книжках почитать можно. а вот те же даты, от приложения к приложению, все слегка отличается.
                          Ответить
    • Полный фЭйл: https://github.com/arhyme/CPP_EVENTS/blob/master/Event.h
      Ответить
    • Нет тебе прощения макросоеб.
      Ответить

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