• Из жизни программиста: Деловые люди

      Приятно работать с деловыми людьми. Работая с ними, в деловой сфере, невольно проникаешься деловым духом. И сам невольно становишься более деловым. Дела ведь требуют делового подхода. Без делового подхода дела не делаются.
      Читать дальше →
      • +37
      • 10.5k
      • 8
    • Долой циклы, или Неленивая композиция алгоритмов в C++

        "Кто ни разу не ошибался в индексировании цикла, пусть первый бросит в деструкторе исключение."

        — Древняя мудрость

        Циклы ужасны. Циклы сложно читать — вместо того, чтобы сразу понять намерение автора, приходится сначала вникать в код, чтобы понять, что именно он делает. В цикле легко ошибиться с индексированием и переопределить индекс цикла во вложенном цикле. Циклы сложно поддерживать, исправлять в случае ошибок, сложно вносить текущие изменения, и т.д. и т.п.


        В конце концов, это просто некрасиво.


        Человечество издревле пытается упростить написание циклов. Вначале программисты подметили часто повторяющиеся циклы и выделили их в отдельные функции. Затем они придумали ленивые итераторы, а потом и диапазоны. И каждая из этих идей была прорывом. Но, несмотря на это, идеал до сих пор не достигнут, и люди продолжают искать способы улучшить свой код.


        Данная работа ставит своей целью пролить свет на отнюдь не новую, но пока что не слишком распространённую идею, которая вполне способна произвести очередной прорыв в области написания программ на языке C++.


        Так как же писать красивый, понятный, эффективный код, а также иметь возможность параллелить большие вычисления лёгким движением пальцев по клавиатуре?

        Читать дальше →
      • Помоги компилятору помочь тебе

          Предисловие


          Современные компиляторы обладают огромным количеством диагностик. И удивительно, что очень малая их часть включена по умолчанию.


          Огромное количество претензий, которые предъявляют к языку C++ в этих ваших интернетах, — про сложность, небезопасность, стрельбу по ногам и т.п., — относятся как раз к тем случаям, когда люди просто не знают о том, что можно решить эти проблемы лёгким движением пальцев по клавиатуре.


          Давайте же исправим эту вопиющую несправедливость, и прольём свет истины на возможности компилятора по предотвращению ошибок.

          Читать дальше →
        • Модульное тестирование, наука и математика


            Предисловие


            Модульное тестирование (unit testing) применяется повсеместно. Кажется, уже никто без него не обходится, все пишут тесты, а их отсутствие в сколь-нибудь серьёзном проекте вызывает, как минимум, непонимание. Однако, многие воспринимают тестирование как некий ритуал, совершаемый для того, чтобы не разгневать "бога программирования". Мол, так надо. Почему? Потому что.


            Буду говорить страшные вещи.


            Не важно, что брать за единицу тестирования. Не важно, как сгруппированы тесты. Не важно, пишутся ли они до кода или после. TDD или не TDD? Всё равно. Доля покрытия? Наплевать. В конце концов, тестов может совсем не быть. Всё это совершенно не важно. Важно, чтобы выполнялись требования, предъявляемые к ПО.


            Модульные тесты — это не ритуал, а хороший, рабочий инструмент, позволяющий приблизиться к выполнению этих требований. И этот инструмент нужно уметь правильно использовать.


            Постойте, причём же тут наука с математикой?
            Читать дальше →
          • Из жизни программиста: Иррациональный подход

              По правде сказать, история эта ни строчки не заслуживает, настолько гнусненькая эта история. Вспоминать противно. Да и не те времена сейчас, чтобы лишний раз вспоминать. Только память расходовать. Это раньше можно было память расходовать, а сейчас не надо. Времена не те.


              И строчки тоже жалко. Это ж сколько коду можно настрочить? Строк пять, не меньше. А то и семь. Если не восемь. Короче говоря, расточительство одно.

              Читать дальше →
            • C++ и CMake — братья навек, часть II

                Дружба навек


                В предыдущей части данного занимательного рассказа говорилось об организации заголовочной библиотеки в рамках генератора систем сборки CMake.


                В этот раз добавим к нему компилируемую библиотеку, а также поговорим о компоновке модулей друг с другом.


                Как и прежде, тем, кому не терпится, могут сразу перейти в обновлённый репозиторий и потрогать всё своими руками.
                Читать дальше →
              • CMake и C++ — братья навек

                • Tutorial

                Дружба навек


                В процессе разработки я люблю менять компиляторы, режимы сборки, версии зависимостей, производить статический анализ, замерять производительность, собирать покрытие, генерировать документацию и т.д. И очень люблю CMake, потому что он позволяет мне делать всё то, что я хочу.


                Многие ругают CMake, и часто заслуженно, но если разобраться, то не всё так плохо, а в последнее время очень даже неплохо, и направление развития вполне позитивное.


                В данной заметке я хочу рассказать, как достаточно просто организовать заголовочную библиотеку на языке C++ в системе CMake, чтобы получить следующую функциональность:


                1. Сборку;
                2. Автозапуск тестов;
                3. Замер покрытия кода;
                4. Установку;
                5. Автодокументирование;
                6. Генерацию онлайн-песочницы;
                7. Статический анализ.

                Кто и так разбирается в плюсах и си-мейке может просто скачать шаблон проекта и начать им пользоваться.
                Читать дальше →
              • Манифест жёсткого программиста


                  Предисловие


                  Данный текст предполагает, что читатель ознакомлен с т.н. agile-манифестом разработки программного обеспечения и его т.н. основополагающими принципами.


                  В настоящий момент существует огромное количество людей, которые принимают данный "манифест", соглашаются с ним, и даже пытаются применять. Но лично для меня это выглядит как шутка, которая затянулась.



                  Содержание


                  1. Манифест жёсткого программиста
                  2. Основополагающие принципы манифеста жёсткого программиста
                  3. Комментарии


                  Манифест жёсткого программиста


                  Мы постоянно открываем для себя более совершенные методы разработки программного обеспечения, занимаясь разработкой непосредственно и помогая в этом другим. Благодаря проделанной работе мы смогли осознать, что:


                  Концепция важнее новых требований
                  Качество важнее скорости
                  Делать как надо важнее, чем делать как просят


                  То есть, не отрицая важности того, что справа, мы всё-таки более ценим то, что слева.

                  Читать дальше →
                • Элементы функционального программирования в C++: композиции отображений


                    Стандартная библиотека языка C++ очень неплоха. Долгие годы стандартные алгоритмы верой и правдой служат простому плюсовику!


                    Но вся отрасль бурно развивается, и язык C++ вместе с ней. Уже давно люди стали понимать, что как бы хороши ни были стандартные алгоритмы, у них есть большой недостаток: нулевая компонуемость. Иначе говоря, невозможно без дополнительных сложностей объединить в цепочку несколько алгоритмов преобразования, фильтрации, свёртки и т.д. и т.п.


                    Существует несколько вариантов решения данной проблемы. Один из них — ленивые вычисления и диапазоны — уже на подходе к стандартной библиотеке.


                    Однако, и старые добрые алгоритмы пока рано списывать со счетов.


                    В этой статье я хочу рассмотреть один из приёмов, который хоть и не является полноценным решением проблемы компонуемости алгоритмов, но вполне способен и упростить работу со старыми стандартными алгоритмами, и обязательно пригодится для работы с грядущими версиями стандарта языка C++.

                    Читать дальше →
                    • +32
                    • 11.5k
                    • 5
                  • Элементы функционального программирования в C++: частичное применение

                      Не буду сильно углубляться в теорию. Что такое частичное применение легко найти в интернете. В том числе на Википедии.


                      Если кратко, то это механизм, позволяющий зафиксировать k аргументов функции от n аргументов, сделав из неё функцию от (n - k) аргументов.


                      // Пусть имеется функция f от четырёх аргументов:
                      int f (int a, int b, int c, int d)
                      {
                          return a + b + c + d;
                      }
                      
                      // Фиксируем первые два аргумента:
                      auto g = part(f, 1, 2); // 1 + 2 + ...
                      
                      // Добрасываем оставшиеся два:
                      assert(g(3, 4) == 10); // ... + 3 + 4 = 10

                      На эту тему уже существует масса публикаций, в том числе и на Хабре:


                      1. C++ Variadic templates. Каррирование и частичное применение
                      2. Частичное применение и каррирование в C++
                      3. Каррируем на C++

                      А ветка "How should I make function curry?" на stackoverflow — просто кладезь для тех, кто впервые сталкивается с этой темой.


                      К сожалению, количество пока не переросло в качество, и хорошего, пригодного к использованию варианта я так и не увидел. При этом любопытно вот что.


                      Замечательный факт №1. В упомянутых статьях присутствуют все техники, которые нужны для реализации правильного (по моему мнению) частичного применения.


                      Надо только всё внимательно проанализировать и сложить кубики в правильном порядке. Именно этим я и собираюсь заняться в данной статье.

                      Читать дальше →
                    • Концепты для отчаявшихся

                        Всё началось с того, что мне понадобилось написать функцию, принимающую на себя владение произвольным объектом. Казалось бы, что может быть проще:


                        template <typename T>
                        void f (T t)
                        {
                            // Завладели экземпляром `t` типа `T`.
                            ...
                        
                            // Хочешь — переноси.
                            g(std::move(t));
                        
                            // Не хочешь — не переноси.
                            ...
                        }

                        Но есть один нюанс: требуется, чтобы принимаемый объект был строго rvalue. Следовательно, нужно:


                        1. Сообщать об ошибке компиляции при попытке передать lvalue.
                        2. Избежать лишнего вызова конструктора при создании объекта на стеке.

                        А вот это уже сложнее сделать.


                        Поясню.

                        Читать дальше →
                      • Динамический неоднородный плотно упакованный контейнер

                          Определение 1. Однородный контейнер – это такой контейнер, в котором хранятся объекты строго одного типа.


                          Определение 2. Неоднородный контейнер — это такой контейнер, в котором могут храниться объекты разного типа.


                          Определение 3. Статический контейнер — это контейнер, состав которого полностью определяется на этапе компиляции.


                          Под составом в данном случае понимается количество элементов и их типы, но не сами значения этих элементов. Действительно, бывают контейнеры, у которых даже значения элементов определяются на этапе компиляции, но в данной модели такие контейнеры не рассматриваются.

                          Определение 4. Динамический контейнер — это контейнер, состав которого частично или полностью определяется на этапе выполнения.


                          По такой классификации, очевидно, существуют четыре вида контейнеров:


                          1. Статические однородные


                            Сможете придумать пример?

                            Обычный массив — int[n].


                          2. Статические неоднородные


                            Примеры?

                            Наиболее яркий пример такого контейнера — это кортеж. В языке C++ он реализуется классом std::tuple<...>.


                          3. Динамические однородные


                            Догадались?

                            Правильно, std::vector<int>.


                          4. Динамические неоднородные


                            Вот об этом виде контейнеров и пойдёт речь в данной статье.


                          Читать дальше →
                        • Поразрядная сортировка с человеческим лицом

                          Несмотря на известность алгоритма поразрядной сортировки, в интернете сложно найти приличную его реализацию на языке C++ (честно говоря, думаю, что и на других языках тоже). Почти всё, что находится поисковиками, чудовищно либо в плане кода, либо в плане эффективности. А чаще всего плохо и то, и другое.

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

                          Возможно, именно поэтому многие люди до сих пор считают поразрядку алгоритмом, представляющим исключительно академический интерес, и малоприменимым в реальности. Однако, это заблуждение.
                          Читать дальше →
                          • +24
                          • 30.8k
                          • 6