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

    +2

    1. 1
    2. 2
    3. 3
    int i = 42;
    foo(i); //не компилируется
    foo(static_cast<int>(i)); //компилируется

    Запостил: raMagPuJI, 05 Марта 2021

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

    • seo: угадайте, когда такое может быть (С++)
      Ответить
      • У меня всё компилируется, попробуй другой конпелятор.

        У int переопределён каст в инт?
        Ответить
        • Например так:

          #include <iostream>
          
          typedef int int_t;
          
          class T {
              public:   
                  T (int_t i) {
                      this->val = i;
                  }
              
                  T () {
                      this->val = 0;
                  }
              
                  explicit operator int_t() {
                      return val;
                  }
              private:
                  int_t val;
          };
          
          void f(int) {
              std::cout << "kokoko 8:^3";
          }
          
          int main() { 
              #define int T
              int i = 42;
              //f(i); не ко-ко-ко конпелируется
              f(static_cast<int_t>(i));
          }
          Ответить
    • > угадайте, когда такое может быть (С++)
      #define static_cast some_shit
      Ответить
      • Например так
        struct shit{int crap;};
        
        template<typename T>
        struct shit some_shit(T s)
        {
          return {s};
        }
        
        void foo(struct shit a)
        {
        }
        
        #define static_cast some_shit
        
        int main()
        {
          int i = 42;
          foo(i); //не компилируется
          foo(static_cast<int>(i)); //компилируется
        }
        Ответить
      • :)) слушай, ну если бы шутка была про дефайн, то я бы её сюда не принес. Понятно, что надефайнить можно всяго
        Ответить
    • void foo(unsigned x) { ... }
      void foo(float x) { ... }
      К примеру.


      А тьфу, ты же в инт и кастишь.
      Ответить
    • .
      Ответить
    • А всё, очень простой ответ же:
      void foo(int&& x);
      i это lvalue, оно в rvalue ref не пролезает. А результат статик каста -- временная хуйня, которая пролезает.
      Ответить
      • и-мен-но!

        можно привести и обратный пример убрав одну &.

        И наконец анекдот
        #include <iostream>
        
        void foo(int&& a) {
                std::cout << "int\n";
        }
        
        void foo(float&& a) {
                std::cout << "float\n";
        }
        
        int main() {
                int i = 1;
                float f = 1.0f;
                foo(i);
                foo(f);
        }


        понятно да, что выведет?)
        Ответить
        • Именно поэтому я против неявных кастов.
          Ответить
          • А есть какие-то ключи, которые их запрещают?
            Ответить
            • «explicit» в объявлении.
              Ответить
              • Но между встроенными типами, увы, не запретить.
                Ответить
                • М-ДА
                  Ответить
                  • Ну оно в некоторых очевидно косячных кейсах предупреждения выдаёт, и на том спасибо.
                    Ответить
                    • почему gcc не выдает ворнинг тут

                      #include <iostream>
                      
                      void foo(int a) {
                              std::cout << a << std::endl;
                      }
                      
                      int main() {
                              foo(3.14f);
                      }
                      Ответить
                      • А хер их знает... В этом случае хотя бы clang ругается. Но с переменной уже всем пофиг.
                        Ответить
                        • Нужно использовать всякую питушню для статического анализа кода. Я думал, что пишу без ворнингов, а потом включил статический анализатор и охуел: оказывается, я всё это время говнокодил )))
                          Ответить
                          • пивас попробуй
                            карповский
                            Ответить
                            • Я сам такое не делаю один раз попробовал пивас (извиняюсь) мне стало не приятно пить

                              У меня другая цель.
                              Управлять компьютерами
                              Ответить
                              • единорог напислся пиваса, и блюет

                                я думал, ты меня поймеш
                                https://www.viva64.com/en/pvs-studio/
                                Ответить
                • Есть питушня «= delete», вроде бы (!!!) с её помощью можно писать функции типа...

                  void koko(int);
                  void koko(short) = delete;
                  void koko(char) = delete;
                  void koko(double) = delete;
                  void koko(float) = delete;


                  И не будет неявного преобразования.
                  Ответить
                  • ванишд
                    Ответить
                  • Будет. Если нет других вариантов (хоть удали хоть просто не пиши) -- значит будет.

                    Ок, и правда работает.
                    Ответить
                    • я сам охуел

                      #include <iostream>
                      
                      void foo(int a) {
                              std::cout << a << std::endl;
                      }
                      
                      //void foo(float a) = delete;
                      
                      int main() {
                              foo(3.14f);
                      }

                      скомпилируй
                      а потом раскоментируй строчку
                      Ответить
                      • Всё, дошло. delete не удаляет перегрузку. Он её создаёт и помечает как запрещённую. Она даже засчитывается как ambigious если ты дабл передашь.
                        Ответить
                        • понятно) я как раз думал, что он удаляет неявно созданные методы.

                          По вумному конечно надо было назвать не delete, а deny, но это же С++

                          всё таки я за С++
                          и за Perl
                          и немного за Ruby

                          программирование должно быть нескучным
                          Ответить
                          • template <typename T>
                            void foo(T x) {
                                static_assert(std::is_same<T, int>::value, "foo supports only ints");
                            }
                            Ответить
                        • А ещё можно подключить шоблон, если нужно сразу много каких-то перегрузок запретить. Смотри какая красота:

                          template <typename T> void function(int, T) = delete;


                          Кресты уже почти как тайпскрипт!
                          Ответить
                          • а зачем тут int?
                            Ответить
                            • Можно и без int, наверное, я долго не разбирался – просто скопировал код со SO.
                              Ответить
                              • >я долго не разбирался – просто скопировал код со SO.

                                всегда так делаю
                                Ответить
                  • Какой удобный язык )))
                    Ответить
                    • Переписал по-удобному, проверь:

                      void f (int x) {
                          return;
                      }
                      
                      template<typename T>
                      void f (T t) = delete;
                      Ответить
                  • Нужна питушня вроде
                    void koko(strict int)
                    Ответить
        • У меня в Си этой хуйни с && нет, именно поэтому я за Си.
          Ответить
        • Я поняле, что происходит, но не понял почему.
          Ответить
          • Для int'овой переменной перегрузка с int&& не катит т.к. переменная lvalue, а && хочет rvalue (значение или временный объект). Тогда конпелятор пробует перегрузку с float&&. Срабатывает неявный каст int во float, а его результат -- временный объект, который является rvalue.

            Ну и для float потом точно так же.
            Ответить
            • Это я понял, но почему не происходит каста int в int&&, а float в float&&?
              Ответить
              • Потому что && ссылки были специально придуманы для случаев, когда ты не хочешь чтобы в них случайно пролезали переменные, которые тебе ещё могут понадобиться.

                Большинство функций, которые принимают &&, это какие-нибудь мув-конструкторы, которые портят аргумент. Поэтому неявного каста из lvalue (переменной) в && нет.
                Ответить
                • А, понял, если скастить int в int&& в foo получится по сути дела lvalue ссылка, отчего теряется смысл &&, а при неявном касте инта во флоат придётся создать временный объект, который как раз и будет будет rvalue?

                  #include <iostream>
                  
                  void foo(int&& a) {
                      a = 5;
                  }
                  
                  
                  int main() {
                      int i = 1;
                      float f = 3.14;
                      foo((int&&)i);
                      std::cout << i << std::endl;
                      foo(f);
                      std::cout << f << std::endl;
                  }
                  Ответить
                  • Как правильно вызвать foo над int?
                    Ответить
                    • foo(std::move(i)), лол. Ну или явный каст в &&, что то же самое, но с более общей сёмантикой.
                      Ответить
                      • Нет, как не испортить i?
                        Ответить
                        • А, ну временную копию отдай на растерзание.

                          foo(int(i)) например. Или какую-нибудь временную локалку мувни.
                          Ответить
                          • А если мувнуть shared_ptr?
                            Ответить
                            • Ну это нормальный паттерн для передачи владения, вай нот?
                              Ответить
                            • если мувнуть шаред птр, то счетчик в итоге останется точно таким же. Старый шарик уже не будет владеть объектом, а новый будет.

                              Шарик в том числе и тем прекрасен, что можно не двигать сам объект. Объект лежит себе в куче, и в ус не дует.
                              Ответить
                    • Доброе утро, руст.
                      Ответить
      • У него же наоборот lvalue не компилируется, а rvalue - да. Или я не понял?
        Ответить
        • почему ты обомне в третьем лице?
          я тут ващето

          foo(i); //не компилируется птому что i (lvalue) не кастится имплистно в rvalue reference
          //без мува
          foo(static_cast<int>(i)); //компилируется бо временная хуйня кастица, она и так rvalue
          Ответить
    • У меня компилируется.
      Ответить
    • Кстати, а чо компилятор C++ даёт скомпилировать методы, у которых указано возвращаемое значение, но при этом ничего не возвращается?
      Ответить
      • думаю (но не уверен) для совместимости с древним "си", где тип можно было не указывать, и подразумевался int.

        вон брмнд подсказывает
        :~$ c++ -Wall 1.cpp
        1.cpp: In function ‘int foo(int)’:
        1.cpp:5:1: warning: no return statement in function returning non-void [-Wreturn-type]
        }
        Ответить
        • Да не, тут причина очень простая -- есть куча кода в котором никто не заморачивался с фейковым возвратом в недостижимых ветках. Поэтому только предупреждение.
          Ответить
          • Не хочу никого обидеть, но выглядит как говно
            Ответить
            • > выглядит как говно

              Именно поэтому свежий код полагается писать с максимальным уровнем предупреждений.
              Ответить
              • Ну то есть это я говно, раз не включил))
                Ответить
                • Незнание законов не освобождает от ответственности.

                  Это как писать на perl без use strict, а потом ругаться, что он любой мусор исполняет.
                  Ответить
                  • Штош, пойду включать ворнинги, ворнинги сами себя не включат
                    Ответить
                  • в перле еще нужно
                    use warnings FATAL => 'all';

                    в JS тоже нужно "use strict";
                    а в TS --strict

                    много где нужно
                    Ответить
            • сложно обидеть крестовика назвав кресты говном, крестовик и сам так думает
              Ответить
            • Ну кстати вот банальный пример:
              void foo(int x) {
                  if (x >= 0)
                      return 1;
                  else
                      return -1;
              
                  // здесь return не нужен т.к. эта точка недостижима
                  // но конпелятор не всегда может это доказать
              }
              Ответить
              • Ты не имел в виду unsigned?
                Ответить
                • Нет. Коммент не про ветку с -1, а про недостижимую ветку где функция закончилась.

                  В этом случае очевидно, что управление туда не попадёт и третий return не нужен. Но в более сложном случае с циклами и т.п. конпелятор часто тупит и просит написать.
                  Ответить
              • Приведи реальный пример.
                Ответить
              • Можно экзепшон кинуть, вдруг у пользователя совсем уж куриный проц, в котором неправильно реализованы JGE, JLE, etc...
                Ответить
                • Ага, а потом тебе конпелятор скажет "код недостижим". Особенно забавно, когда у разных конпеляторов разные мнения по этому поводу.

                  Хотя и с одним случается... Тарас, помнится, тут что-то такое про паскаль постил.

                  Пишешь return -- "код недостижим". Убираешь return -- "не хватает ретурна". И ебись как хочешь.
                  Ответить
                  • в жабах и котлинах иногда приходица псать типа

                    throw new AssertionError("Can't be")

                    или
                    error() в случ коко
                    Ответить
                    • Везёт вам, что один конпелятор.

                      Или в этих языках "код недостижим" в прицнипе нету?
                      Ответить
                      • "код недостижим" есть в любом языке с return =)
                        Ответить
                        • У одновозвратников нету, у них один return в конце функции и он всегда достижим.
                          Ответить
                          • есть языки, которые разрешают только один return?
                            Ответить
                            • Есть языки, где последняя питушня - это return. Можно запретить в кодстайле писать «return» и получить желаемый эффект.
                              Ответить
                              • Хотя нет, пизжу
                                foo = function(x) {
                                  if (x > 0) {
                                    5
                                    7
                                  } else {
                                    6
                                  }
                                }
                                Ответить
                              • > запретить в кодстайле
                                - любой запрет, невозможный с технической точки зрения, есть трата времени
                                Ответить
                                • Проще перейти на питон, где в конце функции просто возвращается None.
                                  Ответить
                                  • запретить функции, которые ничего не развращают
                                    Ответить
                                    • Запретить функции. И конец разврату.
                                      Ответить
                                      • бросить программирование, купить гитару и выступать по ресторанам, как Золотой Хуй
                                        Ответить
                              • да, груви, перл, руби ту нейм фью
                                Ответить
                                • Ещё многие функциональные, конкатенативные япы, если не все.
                                  Ответить
                            • Поэтому я за `логическое программирование'. Там недостижимых веток нет.
                              Ответить
                              • Проктолог?
                                Ответить
                                • Я скорее про Curry думал (это гибрид пролога и хаскеля, если кто не в курсе). Там функции реально могут возвращать значения отовсюду одновременно.
                                  Ответить
                                  • а в коке тоже есть ошмётки логического программирования?
                                    Ответить
                                    • Да/Нет/смотря где/смотря как понимать. Coq это всё-таки пакет из нескольких языков.
                                      В Gallina логического программирования в традиционном смысле нет (т.е. как в прологе), но с другой стороны, этот язык построен на конструктивистской логике по заветам тов. Martin-Löf.
                                      В Ltac есть некое подобие логического программирования в традиционном смысле, там есть pattern-matching c бэктрекингом. (Ltac — это уровень метушни для Gallina.)
                                      Ответить
                                      • А бывают языки построенные на деструктивистской логике?
                                        Ответить
                                      • единственные реальные системы, использующие логическое программирование, про которые я слышал, это, кстати, какие-то там системы управления умными домами на основе Visual Prolog
                                        Ответить
                                  • Изо всех дырок одновременно? Как это?
                                    Ответить
                                    • foo a | a > 1 = 1 -- При a = 2 эта ветка выполняется
                                            | a > 0 = 2 -- И эта тоже
                                      
                                      > foo 2
                                      1
                                      2
                                      Ответить
                                      • А если написать условие всегда ложное?
                                        Ответить
                                        • Тогда функция ничего не вернёт, наверное. И эта, кхм, ветка исполнения отбросится.
                                          Ответить
                                          • Заранее неизвестно же, что там отбросится. Следовательно, компилятор никаких warning'ов выдавать не должен.
                                            Ответить
                                            • > Заранее неизвестно же, что там отбросится.

                                              А вдруг он наинлайнил и узнал?
                                              Ответить
                                          • Т.е. есть всё таки недостижимые ветки.
                                            Ответить
                                      • зачем это надо?
                                        Ответить
                                        • > зачем это надо?

                                          Чтобы не прикручивать костыли в духе linq и не писать перебор вручную.
                                          Ответить
                                          • типа для энумерации на основе фильтров?
                                            Ответить
                                            • для того чтобы уйти от энумерации и получить декларативный язык

                                              разница примерно как между тем чтобы в css написать селектор и тем чтобы жсом ходить по нодам и добавлять и убирать стили
                                              Ответить
                                        • Судя по печальному состоянию компиляторов Curry, это не особо нужно. Олег тупо на монадках и продолжениях нечто подобное запилил.
                                          Ответить
                                          • > Олег

                                            - Филимонов?
                                            Ответить
                                            • шутки про виртуальную реальность из 1996

                                              https://youtu.be/m3HnPEGLiDU?t=491
                                              Ответить
                                            • >Филимонов
                                              https://www.youtube.com/watch?v=nSj44Azbd3o
                                              Ответить
                                              • ты ж питерский, ты митьков должен скидывать, а не люберов

                                                алсо, одного меня бесит, что на ютубе форвард/ревайнд на ёбаные десять секунд?
                                                Ответить
                                                • Ну Дмитрий Шагин же не Филимонов

                                                  А эти вроде химкинские или долгопские
                                                  Ответить
                                            • Ты странный какой-то. Существует только один Олег.
                                              Вот его статья про backtracking на продолжениях: http://okmij.org/ftp/Computation/monads.html#LogicT
                                              Ответить
                                              • Ты что, елозил на хуях Стругацких?

                                                p.s. ах да, это же Лем напейсал.
                                                Ответить
                            • В поцкале вообще ретурна нет. Есть exit, но это немного не то. И Дейкстра его обосрал.
                              Ответить
                              • Точно, Паскаль же умеет в несколько возвращаемых значений.

                                Именно поэтому я за
                                Ответить
                              • В паскале возвращать значение мжет только функция (а не процедура) и вроде как завершение там описывается как

                                funcName := result

                                нет?
                                Ответить
                                • > funcName := result

                                  Да. Но выглядит как ёбаный костыль, как-будто процедуре прикрутили невидимый аргумент по ссылке. А всё ради одновозвратности.
                                  Ответить
                                • Это не завершение, а запись результата.

                                  Завершается функция либо дойдя до конца, либо по exit.
                                  Ответить
                      • >Или в этих языках "код недостижим" в прицнипе нету?
                        есть, но в очень простых случаях

                        if (true) {
                        return;
                        }
                        int a = 1; //скорее всего может не скомпилирвоаться
                        Ответить
                        • Да, гораздо чаще встречается «код непостижим».
                          Ответить
                • http://govnokod.ru/19550
                  Ответить
          • У одновозвратников таких проблем нет, кстати.
            Ответить
            • именно потому шестидесятилетние сишники часто одноразвратники
              Ответить
            • Да, у них код всегда выглядит как говно. Зато единообразно.
              Ответить
            • odnovozvratniki.ru
              Ответить
      • Ворнинги включи.
        Ответить
        • Включился ворнинг: "говно забыло уходить". Гет аут фром хире!
          Ответить

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