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

    +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
    constexpr void foo(int &a, const int b)
    {
      a = b * 2;
    }
    
    constexpr void foo2(int *a, const int b)
    {
      *a = b * 2;
    }
    
    constexpr int shit = []() constexpr {int a = 0; foo(a, 666); return a;}();
    
    constexpr int shit2 = []() constexpr {int a = 0; foo2(&a, 666); return a;}();

    Итак, время обсирать крестоговно. Вот есть там такая фича - можно по ссылке и указателю хуйню через constexpr присваивать. Только вот эта тупая херня под названием лямбда, она обязательно требует инициализации некоторого говна, передаваемого куда-то там, если она объявлена как constexpr. На кой хрен мне что-то инициализировать, если это говно я в constexpr не читаю, а только присваиваю? И сделайте там какие-нибудь write-only переменные, которые через ссылку или указатель пробрасывать можно, ну чисто чтоб поржать

    Запостил: j123123, 23 Февраля 2019

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

    • А если например сделать так:
      int shit = []() {int a; foo(a, 666); return a;}();


      компилятор GCC вам на это нагенерирует херни:
      _GLOBAL__sub_I_shit:
              mov     DWORD PTR shit[rip], 1332
              ret
      shit:
              .zero   4


      https://godbolt.org/z/hMh3qz - проверь
      Ответить
    • Вот например такая херня
      #include <cstdint>
      #include <cstddef>
      
      constexpr uint64_t fib(uint64_t n)
      {
        return (n == 0) ? 0 : ((n == 1 || n == 2) ? 1 : fib(n - 1) + fib(n - 2));
      }
      
      uint64_t shit[10] = 
        []() constexpr
        {
          uint64_t tmp[10] = {0};
          for(size_t i = 0; i < 10; i++)
          {
            tmp[i] = fib(i);
          }
          return tmp;
        }();

      нихуя не работает.
      error: array must be initialized with a brace-enclosed initializer
      Этим тупым говном можно проинициализировать массив вообще? Или тут только поеботу на Сишном Препроцессоре™ писать, генерируя хуйню вида {fib(0), fib(1), fib(2), fib(3), fib(4), fib(5) ... } ?
      Ответить
      • > поеботу на Сишном Препроцессоре™ писать, генерируя хуйню вида

        А он позволяет генерить хуйню длиины N?
        Вот шаблоны позволяют
        Ответить
        • > А он позволяет генерить хуйню длиины N?
          Можно нагенерить хуйни, которая будет работать для хуйни вплоть до N, вот через это говно: http://govnokod.ru/14511

          Еще есть такая вот поебень из буста: https://www.boost.org/doc/libs/1_69_0/libs/preprocessor/doc/ref/repeat.html
          Ответить
          • https://wandbox.org/permlink/Y1gETtfZyP3AvbBk говно какое-то
            Ответить
        • > Вот шаблоны позволяют

          А через шаблон можно проинициализировать массив каким-то таким образом:

          constexpr uint64_t shit[10] = { ТУТ_КАКОЙ_ТО_ГОВНОШАБЛОН<fib, 10> };


          ?
          Ответить
          • Массивы вроде никак. Только std::array.
            Ответить
            • Поэтому я за препроцессор
              Ответить
              • Да это же из-за сишной хуйни про "нельзя возвращать массив". Но внутри структуры почему-то можно.
                Ответить
                • > Да это же из-за сишной хуйни про "нельзя возвращать массив".

                  И из-за ущербности крестовых говношаблонов. Почему через херню на препроцессоре я могу нагенерить инициализацию внутри {} скобок вида хуйня(0), хуйня(1), хуйня(2), https://wandbox.org/permlink/Y1gETtfZyP3AvbBk а говношаблонами это не делается никак? Может быть шаблоны - говно?
                  Ответить
                  • > Шаблоны - говно.
                    А кто-то с этим спорит?

                    З.Ы. std::array можно инициализировать в конпайлтайме, так что похуй на массивы, в общем-то.
                    Ответить
                    • Хуйня какая-то, этот ваш std::array:

                      https://godbolt.org/z/RjzJw8

                      #include <cstdint>
                      #include <array>
                      
                      std::array<std::array<int, 3>, 3> arr = {
                      {
                          {5, 8, 2},
                          {8, 3, 1},
                          {5, 3, 9}
                      }};
                      
                      int arr_c[3][3] =
                      {
                          {5, 8, 2},
                          {8, 3, 1},
                          {5, 3, 9}
                      };
                      
                      int a(size_t x, size_t y)
                      {
                          return arr[x][y];
                      }
                      
                      int a_c(size_t x, size_t y)
                      {
                          return arr_c[x][y];
                      }


                      a(unsigned long, unsigned long):
                              lea     rax, [rdi+rdi*2]
                              lea     rax, arr[0+rax*4]
                              mov     eax, DWORD PTR [rax+rsi*4]
                              ret
                      a_c(unsigned long, unsigned long):
                              lea     rax, [rdi+rdi*2]
                              add     rax, rsi
                              mov     eax, DWORD PTR arr_c[0+rax*4]
                              ret


                      Zero-cost abstraction, говорили они. В сишном варианте на одну lea инструкцию меньше (и вместо нее add). Говно какое-то.
                      Ответить
                      • std::array<std::array<int, 3>, 3> arr = {
                        {
                            {5, 8, 2},
                            {8, 3, 1},
                            {5, 3, 9}
                        }};
                        
                        
                        int a_shit(size_t x, size_t y)
                        {
                            int (*ar_c)[3] = (int (*)[3])&(arr[0][0]); 
                            return ar_c[x][y];
                        }


                        a_shit(unsigned long, unsigned long):
                                lea     rax, [rdi+rdi*2]
                                lea     rax, arr[0+rax*4]
                                mov     eax, DWORD PTR [rax+rsi*4]
                                ret

                        Всё-равно нихрена не оптимизирует. Хуита
                        Ответить
            • Чойта никак? Еще как как! https://akrzemi1.wordpress.com/2017/06/28/compile-time-string-concatenation

              Правда немного в другом виде. Ща попробую накидать.
              Ответить
              • https://wandbox.org/permlink/swWbKZFBzxFReOfR

                Сам код оформлю в отдельное псто.
                Ответить
    • говно
      Ответить
    • Поэтому...
      Скажите ещё, что в "PHP" есть constexpr.
      Ответить
    • "write-only" делается так:
      constexpr auto foo(int b) { return b * 2; }
      constexpr int shit = []() constexpr { return foo(666); }();


      Поебота, которую ты пытаешься сделать есть формальным UB и ненужно. А гениальный план лишь присваивать по ссылке никак не описан в сигнатуре функции (и, надеюсь, никогда не будет).

      Хотя, с другой стороны, такой подход коммитета по ограничению UB в compile-time немного попахивает java...
      Ответить
      • > "write-only" делается так:

        Тогда и constexpr лямбда с ретуртом нафиг не нужен, можно сразу дергать вот ту constexpr функцию, которая сама и так ретурнит. Передавать write-only говно по ссылкам в constexpr-хрень может быть полезно, если надо возвращать из такой функции не одно, а сразу несколько значений. Хотя можно с этим std::tuple подолбиться и ретурнить его, но мне это говно не нравится. Лучше б сделали более однообразно
        Ответить
        • > с этим std::tuple подолбиться

          Если лень писать структурку, которая (своим именем) обьясняет почему эти два значения должны быть вместе.

          Ну и есть еще structured binding, который делает возвращаемые структурки мягкими и шелковистыми:
          auto [x, y, z] = coordinates(object);
          Ответить
          • Кстати, вот реальное говно (причем в стандарте):
            auto [x, y] = []() { return std::pair{1, 2}; }();
            auto l = [x](int z) { return x + z; };
            return l(3);


            https://wandbox.org/permlink/YYMta8qN1n3AzmW5

            GCC конечно хавает, но делает это нелегально.
            Ответить
      • В принципе конпелятор мог бы инициализировать такие переменные каким-нибудь особым "compile time undefined". А потом выдавать ошибку если его прочитали или забыли заменить на нормальное значение.
        Ответить
        • А зачем? Можно сделать так, что если значение неициализированной переменной присвоить другой переменной, та переменная тоже будет "зашкварена" неинициализированностью. И все операции присвоения с той заразившейся неинциализированностью переменной тоже будут "зашкваривать" другие переменные, примерно как NaN в плавучих питухах. И если мы потом из лямбды ретурним что-то неинициализированное или присваиваем эту неинициализированность наружу, в захваченную переменную, то только тогда это можно считать проблемой.
          Ответить
    • зато прикиньте сколько она говна накомпилит с одной строчки :)
      Ответить
    • - Ник, мой Ник. Ник... - шептало мне моё видение. - Ник... Ник...
      Ответить

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