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

    −51

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    void a() 
    {
    }
     
    void b()
    {
      return a();
    }

    Компилится.
    http://ideone.com/8eP1w

    Запостил: HaskellGovno, 13 Июня 2012

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

    • а что, не должно?
      Ответить
    • Это моё говно, которое я час назад выложил на ГД.ру.
      Я проверял, можно ли для процедур делать то же, что и для функций - возвращать результат вызова другой функции. Мало ли, он скажет, что для пустых результатов это недопустимо.
      Ответить
      • Где здесь?!
        И процедур там нет, есть только функции. Эту надо переименовать в helloUB
        Ответить
        • Почему убэ? Надо добавить в a() какое-то действие (вывод текста) и проверить, убэ это или не убэ.
          Ответить
          • никакого ub
            все вызовется как положено
            обычное дело
            странно, что это стало сюрпризом
            Ответить
            • вызовется как положено, а что вернется?
              Ответить
              • вы так говорите, как будто вас смущает и обычный return; из войдовской функции - типа же тоже "вернуть"
                Ответить
                • В том-то и дело, что в процедурах сделано исключение - можно писать return без значения. А тут процедура - и return со значением!
                  Ответить
                  • return a(); в данном случае эквивалентно a(); return;
                    первая запись удобнее, когда происходит
                    if (smth)
                       return a();
                    что явно симпатичнее, чем
                    if (smth) { 
                       a(); 
                       return;
                    }
                    Ответить
                    • На самом деле мне это надо для
                      #if smth
                      #define MY_COOL_TYPE void
                      #else 
                      #define MY_COOL_TYPE int
                      #endif
                      ...
                      MY_COOL_TYPE a() 
                      {
                      ...
                      }
                       
                      MY_COOL_TYPE b()
                      {
                        return a();
                      }
                      Ответить
                      • use templates, luke
                        Ответить
                        • Как?
                          Ответить
                          • ну если твой гипотетический пример, то
                            template <class R>
                            R a() {...}
                            
                            template <class R>
                            R b() { return a<R>(); }

                            но в подавляющем большинстве случаев шаблонные типы выводятся из аргументов (которых у тебя нет) и потому явного указания не требуют
                            Ответить
                            • И как это применить к моему случаю?
                              Вот смотри, под маздайкой главфункция возвращает int, под андрюшкой void, дальше, внутри главфункции сразу вызвается return RunApp(APP_PARAMS), которое имеет свою реализацию для и андрюшки, и маздайки. Тут на шаблонах не сделать, только препроцессором.
                              Ответить
                              • главфункция - это main?
                                или ты мне про какие то непреодолимые разногласия в api?
                                они должны разруливаться api-wrapper, да, не без препроцессора - чтобы совсем сокрыть чужеродный код от компилятора, который его не поймет, но на уровне использования всё должно выглядеть единообразно, тонкости реализации (и в т.ч. что конкретно возвратит тот или иной апи вызов) не должны вылезти за интерфейс этого враппера
                                Ответить
                                • В главном файле проекта препроцессора нет.
                                  На уровне использования всё выглядит как просто возврат значения, возвращаемого внутренней функцией.
                                  Для андрюшки это значение имеет тип void.
                                  Ответить
                                  • для неконсольного приложения на С++ код возврата имеет очень мало смысла, поэтому ты как-нибудь переживёшь ворнинг компилятора про void main и примешь его за данность
                                    ну а RunApp сможешь объявить как void на обеих платформах

                                    или тривиальней:
                                    http://ideone.com/e0WnS
                                    Ответить
                                    • Во-первых, работает и так, и без предупреждений от компилятора. А во-вторых, в студии void WinMain(всякая херня) вообще не скомпилируется:
                                      c:\Users\TarasB\Documents\Visual Studio Projects\Test_Krestoproject\Test_Krestop roject.cpp(4): error C2371: 'WinMain' : redefinition; different basic types
                                      c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include\WinBase.h(1 574) : see declaration of 'WinMain'
                                      "Или тривиальнее" - и как это написать кроссплатформенно, на засунув препроцессор поглубже?
                                      Ответить
                                      • Т.к. у вас RunApp(APP_PARAMS) имеет свою реализацию для и андрюшки, и маздайки (и нужная видимо выбирается препроцессором), то предлагаю нужный для текущей платформы main тоже выбрать препроцессором.

                                        Или даже, возможно, подумать о двух модулях main_android и main_win, из которых на каждой платформе будет собираться только один.

                                        Если же runApp отличаются только возвращаемым значением - то пускай runApp всегда возвращает int. А выбранный препроцессором main уже разберется - возвращать ему это значение или просто выкинуть его.
                                        Ответить
                                        • Да, главная функция совсем разная на каждой платформе. Но делать всю функцию одним макросом я не могу, так как где-то в ней же должны быть места, определяющие обработчики событий. Можно сделать макрос с параметрами, но это не так удобно, как функция с параметрами - для функции подсказка наглядее высветит типы и имена.
                                          И требование - отсутствие препроцессора в главном файле.
                                          Ответить
                                          • Вот так не устроит?
                                            [code=c++]
                                            #ifdef WE_ARE_ON_ANDROID
                                            int runApp(...args...) {
                                            ... runApp for android ...
                                            }
                                            void main()
                                            {
                                            runApp(...);
                                            }
                                            #else
                                            int runApp(...args...) {
                                            ... runApp for win32 ...
                                            }
                                            int main()
                                            {
                                            return runApp(...);
                                            }
                                            #endif
                                            > И требование - отсутствие препроцессора в главном файле.
                                            А в чем причина, если не секрет?

                                            ПыСы: если они совсем разные - ну может правда сделать 2 разных файла, которые будут выбираться системой сборки?
                                            Ответить
                                            • Твоё решение переносит препроцессор в главный файл.
                                              Это значит, что каждый раз при написании новой программы я буду по новой городить вот это вот #if и так далее...
                                              И препроцессор в главном файле это уродливо и ваще. Вот я даже руководство "как использовать SDL под андрюшку читаю", и там пишут "а для андрюшки главный файл надо будет слегка переписать вот так-то", но это же тьфу, криво как-то.
                                              Ответить
                                              • А кто мешает запилить несколько реализаций главного файла для разных платформ (заняться этим 1 раз). Затем оформить их в виде либы, или, возможно, тупо копировать в новые проекты без изменений. В новых проектах достаточно будет запиливать новый int runApp()...
                                                Ответить
                                                • Запилю я файл с главной функцией. Запихну я тело функции (полностью) в макрос DO_ALL.
                                                  И как этот макрос вызывать? Где обработчики выставлять?
                                                  Ответить
                                                  • Какой еще макрос DO_ALL?
                                                    Ответить
                                                    • Ну который содержит полностью и объявление и тело главной функции.
                                                      Ответить
                                                      • > Ну который содержит полностью и объявление и тело главной функции.
                                                        За каким х.ем он его содержит?
                                                        // main_android.cpp
                                                        #include "app.h"
                                                        void main()
                                                        {
                                                            App app;
                                                            app.run();
                                                        }
                                                        // main_windows.cpp
                                                        #include "app.h"
                                                        int WINAPI WinMain(...всякий хлам...) {
                                                            App app;
                                                            return app.run();
                                                        }
                                                        // app.h
                                                        class App {
                                                        public:
                                                            int run();
                                                        };
                                                        // app.cpp или же app_android.cpp и app_win.cpp по отдельности
                                                        int App::run() { ... }

                                                        Какие файлы компилировать, а какие нет - настроите в проектах\мейкфайлах\что-там-у-вас.
                                                        Ответить
                                                        • А, выставляете обработчики через глобальные переменные, которые надо самому же и создавать в главном файле. Мне это решение тоже не понравилось, опять же по причине отсутствия самодокументируемости (как и решение с макросом с параметрами).
                                                          Ответить
                                                          • > выставляете обработчики через глобальные переменные
                                                            Обработчики чего?
                                                            Ответить
                                                            • Обработчики событий, то есть то, что отличает одну программу от другой. Без них все программы были бы абсолютно одинаковыми - показывали бы пусток окно и закрывались по крестику.
                                                              Ответить
                                                              • А что они делают в main? Я думал они уже разруливаются в run() независимо от текущей платформы...
                                                                Ответить
                                                                • А, всё, понял. То есть архитектура получется как у меня, только наоборот. Да, тоже вариант.
                                                                  Ответить
                                          • на каждой платформе заводи свой файл в котором объявляй нужный на этой платформе main. при компиляции файлы лишних платформ не включаешь в набор компилирующихся и линковщик сам разберется.
                                            Ответить
                                            • Мы уже обсудили этот вариант, особых преимуществ над своим не вижу, чтобы менять.
                                              Ответить
                                        • > А выбранный препроцессором main уже разберется
                                          если уж делать два файла - пускай разбирается система сборки (даже в том же студийном проекте можно для разных конфигураций задать компилировать этот cpp или исключить из построения)
                                          Ответить
                                          • Два файла и система сборки? Полностью засунуть тело Main в препроцессор я не могу, потому что я должен где-то задавать обработчики, и желательно не в параметрах макроса.
                                            Ответить
                                            • > Полностью засунуть тело Main в препроцессор я не могу
                                              тебе нужно main_win.cpp, main_android.cpp, app_win.cpp, app_android.cpp
                                              последние два отвечают единому интерфейсу app.hpp (если и интерфейс app у тебя разный, то опять же app_{win,android}.hpp - по мере распухания различий я бы посоветовал завести параллельные папки win32/ и android/, куда класть уже нормальные main.cpp, app.cpp, etc - в студии есть фильтры, которые можно вручную заводить так, чтобы они соответствовали структуре папок)
                                              в системе сборки для конфигурации win32 для *_android.cpp выставляешь "исключить из построения"
                                              done
                                              Ответить
                                          • Ну я собственно об этом писал строчкой выше процитированной фразы.
                                            Ответить
                                            • Блин из-за этой линеаризации комментов хрен поймешь, кто кому что пишет :(
                                              Ответить
                • а, всё, я обсмотрелся
                  Ответить
        • Тарас же! Величайший паскалист нашего времени. Отсюда и процедуры...
          Ответить
      • >Это моё говно, которое я час назад выложил на ГД.ру.
        Быстрое нынче Гумно пошло - резкое как понос.
        Ответить
    • g++-4.5 -Wall -Wextra -pedantic-errors

      gcc-4.5 -std=gnu99 -Wextra -Wall -pedantic-errors
      error: ISO C forbids ‘return’ with expression, in function returning void
      Ответить
      • да, не первый случай, когда ограничения стандарта снисходительно игнорируются компиляторами в пользу людей
        С11-n1548:
        6.8.6.4 The return statement
        Constraints
        1. A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.

        стандарт С++ в этом плане более мягкий:
        6.6.3 The return statement
        3 A return statement with an expression of type “cv void” can be used only in functions with a return type of cv void; the expression is evaluated just before the function returns to its caller.
        Ответить
        • В с++ видимо ослабили проверку для удобства разработки шаблонов (не нужно делать отдельную специализацию под возвращаемый void)?
          Ответить
          • возможно, в том числе
            мне кажется вполне здравым пользоваться таким return a(); даже не в шаблонах и не стыдиться этого
            Ответить
    • Одна из проблем языков, делающих упор на statements, а не на expressions - пресловутый void. Мне кажется, наличие типа Unit делает язык более последовательным и удобным для понимания и использования. В жабе вон для дженериков придумали класс Void без экземпляров (только null только хардкор), который выглядит как костыль.
      Ответить
      • так уж сложилось исторически
        да и не факт, что возможность получения вычисленного значения из if/case, for/while/do врядли бы сделала с++ более
        > удобным для понимания
        Ответить
      • Ну void в с++ отличается от unit type только тем, что нельзя описать переменную, поле или аргумент функции типа void. Такая возможность, конечно, была бы удобна в шаблонах, а в остальном коде разница, имхо, не заметна (все равно операций кроме присваивания и, возможно, сравнения, всегда возвращающего true, над ним не было бы).
        Ответить
      • >В жабе вон для дженериков придумали класс Void без экземпляров (только null только хардкор), который выглядит как костыль.
        Сучата. Тоже ощущение костыльности и бесполезности типа из-за небходимости возврата этого самого null.
        Ответить
    • главное, что типы совпадают
      Ответить
    • Возможность делать такой return - специфическая фича С++, помогающая, в частности, в написании generic кода (т.е. шаблонного кода). В С такое запрещено, что, кстати, иногда мешает.
      Ответить

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