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

    +1

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    template<typename T>
    class IsClassT {
      private:
        typedef char One;
        typedef struct { char a[2]; } Two;
        template<typename C> static One test(int C::*);
        // Will be chosen if T is anything except a class.
        template<typename C> static Two test(...);
      public:
        enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
        enum { No = !Yes };
    };

    Как эта поебота работает?
    Что такое "int C::*"?

    Запостил: A3APTHblu_nemyx, 19 Марта 2019

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

    • #include <iostream>
      using namespace std;
      
      template<class T>
      struct IsChar {
          static bool value;
      
          static char foo(char c) {return true;}
      
          static int foo(...) {return false;}
      
          template<class C>
          static bool bar() {
              return foo(C());
          }
      };
      
      template<class T>
      bool IsChar<T>::value = IsChar<T>::bar<T>();
      
      struct Hui {
      };
      
      int main() {
          cout << IsChar<char>::value << endl;
          cout << IsChar<int>::value << endl;
          cout << IsChar<Hui>::value << endl;
      }


      какого хуя?
      Ответить
      • Именно поэтому я за «PHP».
        Ответить
      • SFINAE не срабатывает при C == int потому что int можно передать в foo(char).
        Ответить
        • Меня больше бесит, что uint8_t выводится в стрим как символ, а не как число.
          Ответить
          • Комитет тебя услышал и ввёл тип std::byte!

            …его, правда, в стрим вообще выводить нельзя.
            Ответить
      • Именно поэтому я за "Си":
        #include <stdio.h>
        
        #define CAT_(x, ...) x ## __VA_ARGS__
        #define CAT(...) CAT(__VA_ARGS__)
        
        #define CHECK_N(x, n, ...) n
        #define CHECK(...) CHECK_N(__VA_ARGS__, 0)
        #define PROBE(x) x, 1
        
        #define IS_CHAR(t) CHECK(CAT_(IS_CHAR_, t))
        #define IS_CHAR_char PROBE(~),
        
        #define QUOTE_(...) #__VA_ARGS__
        #define QUOTE(...) QUOTE_(__VA_ARGS__)
        
        #define PRINT(...) puts(QUOTE(__VA_ARGS__))
        
        int main(void)
        {
            PRINT(IS_CHAR(char), IS_CHAR(int), IS_CHAR(char**));
            return 0;
        }
        https://ideone.com/B4EWWS
        Ответить
        • Не знаю, как сделать, чтобы char** и т.п. возвращали 0 :(
          Ответить
          • Я зделяль:
            #include <stdio.h>
            
            #define CAT_(x, ...) x ## __VA_ARGS__
            #define CAT(...) CAT(__VA_ARGS__)
            
            #define CHECK_N(x, n, ...) n
            #define CHECK(...) CHECK_N(__VA_ARGS__, 0)
            #define PROBE(x) x, 1
            
            #define IS_CHAR(t) CHECK(CAT_(IS_CHAR_, t(~,1)))
            #define IS_CHAR_char(...) __VA_ARGS__
            
            #define QUOTE_(...) #__VA_ARGS__
            #define QUOTE(...) QUOTE_(__VA_ARGS__)
            
            #define PRINT(...) puts(QUOTE_(__VA_ARGS__))
            
            int main(void)
            {
                PRINT(IS_CHAR(char), IS_CHAR(int), IS_CHAR(char**), IS_CHAR(char(*)()));
                return 0;
            }
            https://ideone.com/ZHLHCI
            Ответить
        • template <typename>
          struct is_char : std::false_type {};
          
          template <>
          struct is_char<char> : std::true_type {};
          
          int main() {
            static_assert(is_char<char>() && !is_char<int>() && !is_char<char**>() && !is_char<char(*)()>());
          }


          https://wandbox.org/permlink/xKirxHNm6Rbx8ePR
          Ответить
          • #include <type_traits>
            
            template<typename T>
            constexpr bool is_char = std::is_same_v<T, char>;
            
            int main() {
              static_assert(is_char<char> && !is_char<int> && !is_char<char**> && !is_char<char(*)()>);
            }


            https://wandbox.org/permlink/g46U2AeBTyx6Qcqy
            Ответить
            • Оно то да. Мое было в качестве иллюстрации. Просто лень за пятку укусила писать constexpr static bool value = true/false, потому заюзал boilerplate из std::integral_constant
              Ответить
            • ИДИТЕ НАХУЙ СО СВОИМИ ШОЬЛОНАМИ! Я ЗА МОКРОСЫ!
              Ответить
              • СОЗДАЙ СВОЙ ТРЕД ПРО МОКРОСЫ И ТЕКИ ТАМ
                А ЗДЕСЬ ТЕКУТ ПО "SFINAE"
                Ответить
          • Это я уже понял. Как сделать со "SFINAE"?
            Ответить
            • Зачем тебе тут SFINAE? Ты хочешь его понять на таком примере?

              Я тебе вот чтоб скажу: чтоб понять SFINAE, надо сначала понять SFINAE. Substitution failure is not an error. Т.е. если подставить в шаблон некие параметры а в результате выходит поеботня, шаблон игнорируется, а не выдается ошибка компиляции.

              Другими словами, SFINAE нужен чтоб в некоторых ситуациях игнорировать один шаблон (специально создавая невалидный код) чтоб использовать другой в некоторых ситуациях.
              Ответить
            • Как то так, крч.
              template <typename>
              struct sfinae {};
              
              template <>
              struct sfinae<char> { using type = std::true_type; };
              
              template <typename T>
              struct is_char {
              private:
                template <typename U>
                constexpr static typename sfinae<U>::type check(U*);
                template <typename U>
                constexpr static std::false_type check(...);
              public:
                constexpr static bool value = decltype(check<T>(nullptr)){};
                constexpr operator bool() const { return value; }
              };
              
              int main() {
                static_assert(is_char<char>() && !is_char<int>() && !is_char<char**>() && !is_char<char(*)()>());
              }


              https://wandbox.org/permlink/kQhjVGRHQZRYVbjD

              Поэтому я за "обдуманный выбор средств решения задачи".
              Ответить
            • Вот хороший пример работы SFINAE:
              #include <iostream>
              #include <iomanip>
              #include <vector>
              
              template<typename T>
              auto my_begin(T & t) -> decltype(t.begin())
              {
                  return t.begin();
              }
              
              int main()
              {
                  std::vector<int> a{};
              
                  auto x = my_begin(a);
                  std::cout << std::boolalpha << (x == a.begin()) << std::endl;
              
                  int b = 1;
                  auto y = my_begin(b);
              
                  return 0;
              }

              https://wandbox.org/permlink/Sv1dM02fs4ijHRQn

              Конпелятор ругается не на то, что у переменной b нет метода begin, а на то, что подходящая перегрузка не найдена:
              prog.cc:19:24: error: no matching function for call to 'my_begin(int&)'


              И дальше он поясняет за SFINAE:
              prog.cc:6:6: note:   template argument deduction/substitution failed:
              prog.cc: In substitution of 'template<class T> decltype (t.begin()) my_begin(T&) [with T = int]':
              prog.cc:19:24:   required from here
              prog.cc:6:36: error: request for member 'begin' in 't', which is of non-class type 'int'
                  6 | auto my_begin(T & t) -> decltype(t.begin())
                    |                                  ~~^~~~~

              То есть при поиске перегрузки шаблон был проигнорирован, потому что при подстановке int в качестве T происходит ошибка.
              Ответить
              • А «clang» ещё понятнее поясняет:
                prog.cc:19:14: error: no matching function for call to 'my_begin'
                    auto y = my_begin(b);
                             ^~~~~~~~
                prog.cc:6:6: note: candidate template ignored: substitution failure [with T = int]: member reference base type 'int' is not a structure or union
                auto my_begin(T & t) -> decltype(t.begin())
                     ^                            ~
                Ответить
                • Не люблю шланг, он часто обламывает мои мокроёбства.
                  Ответить
                  • показать все, что скрытоvanished
                    Ответить
                    • Складывается впечатление, что ты постоянно течёшь.
                      Ответить
                      • В контексте языков без сборки мусора, течь -- не очень-то и хорошо, а если точнее -- очень плохо.
                        Ответить
                        • Для языков со сборкой мусора - ещё хуже.
                          Ответить
                        • Именно поэтому я за "PHP".
                          Ответить
                        • показать все, что скрытоvanished
                          Ответить
                          • Щито?
                            Свифт течёт, или я не правильно тебя понял? В удаление циклических ссылок сейчас каждый говноязык умеет, даже "PHP".
                            Ответить
                            • показать все, что скрытоvanished
                              Ответить
                              • Какой багор )))
                                Поэтому я за "PHP".
                                Ответить
                                • показать все, что скрытоvanished
                                  Ответить
                                • показать все, что скрытоvanished
                                  Ответить
                                  • показать все, что скрытоvanished
                                    Ответить
                                    • Никто не мешает COM-файлу выделять память через диспетчер памяти операционной системы и оперировать с этими блоками через длинные указатели.

                                      Можно захавать всю оперативку, доступную досовским программам, а потом вызвать функцию «Terminate & stay resident» и остаться в памяти.
                                      Ответить
                                      • показать все, что скрытоvanished
                                        Ответить
                                        • Через INT 21H. Или тебя функция интересует? Гугли MCB —– «memory control block».

                                          P.S. Функция 48H –— выделить блок (BX=кокококоличество параграфов); 49H –— освободить блок (ES=сегментная часть адреса блока).
                                          Ответить
                                      • показать все, что скрытоvanished
                                        Ответить
                                        • Нет. Так только на старте программы. Ты можешь направить сегментный регистр куда угодно.

                                          Как по-твоему COM-файлы читали состояние светодиодов Caps Lock, Num Lock, Scroll Lock из нулевого сегмента?
                                          Ответить
                                          • показать все, что скрытоvanished
                                            Ответить
                                            • Ну ещё COM-файлы срали в видеопамять, которая в другом сегменте.

                                              Модель TINY гарантирует только то, что CS=SS=DS на старте программы, а потом ты можешь крутить сегменты, как хочешь (в рамках разумного, конечно, чтобы ничего не сломать).
                                              Ответить
                                              • показать все, что скрытоvanished
                                                Ответить
                                                • Да, весь твой код + инициализированные переменные должны влезать в 64К. Да и неинициализированные тоже...

                                                  Потом ты можешь честно попросить ещё немного памяти через INT 21H, AH=48H и работать с полученным блоком, а можешь и нагло распидорашивать весь первый мегабайт оперативки, включая код самой «DOS» или, например, shadow copy видеобиоса (чтобы шрифты поменять).
                                                  Ответить
                                                  • показать все, что скрытоvanished
                                                    Ответить
                                                    • Если в DOS 1.0 не было MCB, то и программу из программы вызывать было нельзя? Если память не размечена на свободную и занятую, то нельзя определить, куда можно загружать дочернюю программу и куда она может срать.

                                                      Или программы в DOS 1.0 использовали только ту память, которую им дали при старте, и больше никуда по соглашению не срали?
                                                      Ответить
                                                      • показать все, что скрытоvanished
                                                        Ответить
                                                      • показать все, что скрытоvanished
                                                        Ответить
                                                        • >> 04h load and execute in background (European MS-DOS 4.0 only)

                                                          «European MS-DOS 4.0» –— это многозадачная версия «DOS», выпущенная по заказу «Siemens». Редкая вещь. Ни в файлообменниках, ни в P2P-сетях, ни на компакт-дисках я её не видел.
                                                          Ответить
                                                          • показать все, что скрытоvanished
                                                            Ответить
                                                            • Не знаю.

                                                              Для сравнения: «DR-DOS» поставлялся с программой «multitasker». Многозадачность была вытесняющей: программы он переключал принудительно по таймеру. Как было с памятью, не в курсе.

                                                              «MS-DOS» поставлялся с графической (но не оконной, а полноэкранной) оболочкой «DOSSHELL». У «DOSSHELL» был ручной переключатель задач: можно было запустить одну программу, поработать в ней, через «Alt+Tab» переключиться на другую, поработать в ней, потом переключиться обратно. Неактивную программу «DOSSHELL» мог высрать в своп-файл, чтобы сэкономить память («одновременно» запущенные программы всё равно друг друга не видели).

                                                              И это всё было в реальном режиме (или в V86, если был запущен EMM386). Хотя стоп, дурдосовский мультитаскер (в отличие от «DOSSHELL») работал только с EMM386, значит, виртуальный режим ему для чего-то был необходим.
                                                              Ответить
                                                              • показать все, что скрытоvanished
                                                                Ответить
                                                                • Да, EMS переключал DOS с его приложениями в V86, а в диапазон адресов где-то между окошком видеопамяти и BIOS отображал окошко размером 32 или 64 килобайта в доступную ему оперативку. Вызовами API EMS это окошко можно было отображать на произвольный адрес, доступный защищённому режиму.

                                                                  XMS позволял оставлять DOS в реальном режиме и лишь при вызове API кратковременно переключался в защищённый режим, копировал нужный кусок памяти из памяти защищённого режима в память реального режима (т. е. куда-то в первый мегабайт) или обратно, а потом обратно переключался в реальный.

                                                                  Dos4GW –— это одна из реализаций DPMI (их было море).

                                                                  Была ещё такая штука:
                                                                  https://en.wikipedia.org/wiki/DOS_Protected_Mode_Services

                                                                  Использовалась редкими программами вроде Stacker/Doublespace/Drivespace (сжатие досовских дисков на лету) и некоторыми драйверами мыши.
                                                                  Ответить
                                                                • Ещё был «нереальный» режим, который не рекомендовалось использовать (я видел только одну программу-демку, которая его использовала). Суть «нереального режима»: переключаемся в защищённый, ставим лимиты у всех сегментов по 4 гигабайта, возвращаемся в реальный и пишем в память за пределами первого мегабайта с помощью префикса длины адреса (добавляем 67H перед КОП).

                                                                  «Нереальный» режим почти никем не использовался, потому что такие программы были несовместимы с EMS, DPMI и с Windows.
                                                                  Ответить
                                                              • > для чего-то
                                                                Чтобы не копировать первый мегабайт при каждом переключении контекста?
                                                                Ответить
                                                                • Вот и я об этом подумал.

                                                                  «Досшелл» не нужно быстрое переключение задач, поскольку там задачи переключаются по запросу пользователя. Он может работать и в реальном режиме, свопуя первый мегабайт на диск.

                                                                  «Мультитаскер» же с его многозадачностью реального времени должен переключаться быстро, поэтому он переходит в V86 и мапит первый мегабайт для каждого приложения на разные области расширенной памяти. Ему для переключения не надо копировать блоки памяти, достаточно только пошаманить с таблицей дескрипторов.
                                                                  Ответить
                                                        • Тут ещё упомянули «Desqview» –— это многозадачная оконная оболочка для досовских программ, по концепции похожая на «Windows 3.x». Эта оболочка ещё предоставляла API. Могла бы дорасти до полноценной ОС, но не сложилось.

                                                          Была ещё оболочка «GEM», которая тоже была внешне похожа на «Windows 3.x»...
                                                          Ответить
                                                  • > Да и неинициализированные тоже
                                                    a equ byte [es:0000]
                                                    b equ word [es:0001]
                                                    Ответить
                                                    • Настоящий шаман, однако!

                                                      Для таких переменных не нужны фиксапы (потому что смещение фиксировано), если es тоже фиксирован либо вычисляется, а не указывает на саму программу. Поэтому такие переменные можно использовать даже в com-файле.
                                                      Ответить
                                                • P.S. Погугли макрос MK_FP, чтобы узнать, как в «Бройлер Си» дотягивались до чужих сегментов.
                                                  Ответить
                            • Кстати, любители обмазываться "shared_ptr" и "unique_ptr" таким же образом могут соснуть?
                              Ответить
                              • показать все, что скрытоvanished
                                Ответить
                                • > я не крестоблядь
                                  Но всё верно рассказал же.

                                  weak_ptr помогает shared_ptr поддерживать граф владения ацикличным.

                                  А из unique_ptr просто не стоит лепить что-то сложнее дерева (т.к. он с weak не взаимодействует).
                                  Ответить
                                  • > weak_ptr, shared_prr, unique_ptr
                                    Блядь, как всё сложно... Именно поэтому я за "C".
                                    Ответить
                          • Интересно, а питоневский
                            a = []
                            a[0] = a
                            будет жить вечно?
                            Ответить
                            • Если я заменю батарейки.
                              Ответить
                            • Конечно же {}, со списком нада append, я перепутао.

                              Кстати, в 'J' значения всех типов неизменяемые, но можно делать циклические сцылки в локалях или объектах (которые основаны на локалях):
                              hui =: <'hui'
                                 na__hui =: hui
                                 hui
                              ┌───┐
                              │hui│
                              └───┘
                                 na__hui
                              ┌───┐
                              │hui│
                              └───┘
                                 na__na__na__na__na__hui
                              ┌───┐
                              │hui│
                              └───┘
                                 coclass 'petushara'
                                 petushara =: conew 'petushara'
                                 blyad__petushara =: petushara
                                 petushara
                              ┌─┐
                              │0│
                              └─┘
                                 blyad__petushara
                              ┌─┐
                              │0│
                              └─┘
                                 blyad__blyad__blyad__blyad__petushara
                              ┌─┐
                              │0│
                              └─┘
                              Ответить
    • > Что такое "int C::*"?
      https://en.cppreference.com/w/cpp/language/pointer#Pointers_to_data_members
      Это указатель на член класса C.

      > Как эта поебота работает?
      Магия — в выражении «sizeof(IsClassT<T>::test<T>(0)) == 1». Когда компилятор его встречает — он начинает искать перегрузку метода «test», которая может принять «0».

      Сначала компилятор пытается инстанцировать шаблонную функцию «One test(int C::*)» — принимающую указатель на целочисленный член класса C и возвращающую объект типа One.

      Если C — это класс, то объявление «One test(int C::*)» валидно, и компилятор рассматривает эту перегрузку. Он видит, что других подходящих перегрузок нет («test(...)» компилятор проигнорирует, поскольку имеется подходящая перегрузка с фиксированным числом параметров), а потому размер выражения «IsClassT<T>::test<T>(0)» будет равен размеру «One».

      Если C — это не класс, то объявление «One test(int C::*)» — это ошибка. Однако, по правилу SFINAE, компиляция не упадёт, а компилятор продолжит поиск подходящей перегрузки. Поскольку других объявлений «test» нет, будет выбран вариант с «...», а размер «магического выражения» станет равным двум (sizeof(Two)).
      Ответить
      • Простой пример SFINAE — это «std::enable_if», который реализован как-то так:
        template<bool B, class T = void>
        struct enable_if {};
         
        template<class T>
        struct enable_if<true, T> { typedef T type; };


        А используется так:
        #include <iostream>
        #include <type_traits>
         
        template<typename T>
        typename std::enable_if<(sizeof(T) > 4), void>::type isBig()
        {
            std::cout << "Yes! T is big!" << std::endl;
        }
         
        template<typename T>
        typename std::enable_if<(sizeof(T) <= 4), void>::type isBig()
        {
            std::cout << "No! T is tiny!" << std::endl;
        }
         
        int main()
        {
            isBig<char[42]>();
            isBig<char>();
         
            return 0;
        }
        Ответить
        • Какой тип возвращает isBig?
          Ответить
          • Если первый шаблонный аргумент (B) в enable_if равен true — то тот тип, который указан вторым аргументом в enable_if (T, в примере — void). Если же B == false, то никакой — в таком экземпляре enable_if не будет типа enable_if::type, получим ошибку компиляции, которая будет проигнорирована по правилу SFINAE.
            Ответить
        • А я понял. Если false, то type будет неопределён, и кусок не скомпилица.
          Ответить
      • > Если C — это класс, то объявление «One test(int C::*)» валидно

        Оно валидно, т.к. 0 кастится к нулевому указателю? А если не класс, то у него не может быть указателя на член?
        Ответить
        • Угу, причём содержимое класса неважно — достаточно того, что это класс.
          #include <iostream>
          #include <cstdlib>
           
          class C {
          	float pituh = 0.0f;  // Note: float
          };
           
          void func(int C::* ukozatel)
          {
          	std::cout << "Ukozatel == " << ukozatel << std::endl;	
          }
           
          // void func(int float::* ukozatel)
          // {
          // 	std::cout << "Ukozatel == " << ukozatel << std::endl;	
          // }
           
          /*
          prog.cpp:13:15: error: cannot combine with previous 'int' declaration specifier
          void func(int float::* ukozatel)
                        ^
          prog.cpp:13:20: error: 'ukozatel' does not point into a class
          void func(int float::* ukozatel)
          */
           
          int main()
          {
          	func(0);
          	return EXIT_SUCCESS;
          }

          https://ideone.com/u70mS9
          Ответить
    • Это указатель на любой член класса типа int.
      Ответить

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