<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Блоги: заметки с тегом cpp</title>
<link>https://blogengine.me/blogs/tags/cpp/</link>
<description>Автоматически собираемая лента заметок, написанных в блогах на Эгее</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.0 (v4079e)</generator>

<itunes:subtitle>Автоматически собираемая лента заметок, написанных в блогах на Эгее</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit>no</itunes:explicit>

<item>
<title>Си++: форматированный вывод (продолжение)</title>
<guid isPermaLink="false">119190</guid>
<link>https://bolknote.ru/all/si-formatirovanny-vyvod-prodolzhenie/</link>
<pubDate>Sun, 07 May 2023 23:43:13 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/si-formatirovanny-vyvod-prodolzhenie/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Очень раздражает, что вместо того, чтобы писать прикладной код, я вынужден бороться с компиляторами, да не с одним, а с тремя, под разные операционные системы. Я как будто пытаюсь писать не на одном языке, а сразу на трёх, похожих, но не полностью.&lt;/p&gt;
&lt;p&gt;Мои приключения c &lt;a href="https://bolknote.ru/all/si-formatirovanny-vyvod/"&gt;форматированным выводом&lt;/a&gt; в Си++ до сих пор не закончились, оказалось, что последний вариант обёртки над &lt;tt&gt;std::snprintf&lt;/tt&gt; в одном из компиляторов не собирается с одним из видов аргументов, пришлось его обернуть в &lt;tt&gt;std::cref&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Умные люди в комментариях советуют перейти на внешнюю библиотеку &lt;a href="https://github.com/fmtlib/fmt"&gt;&lt;i&gt;fmt&lt;/i&gt;&lt;/a&gt; и я уже сделал подход к снаряду, но под &lt;i&gt;mingw&lt;/i&gt; у меня сборка пока не заработала. Завтра попытаюсь ещё раз — хочу подключить библиотеку подмодулем к своему репозиторию встроить компиляцию в процесс сборки своего проекта. Мне кажется, что я делаю всё правильно, а вот &lt;i&gt;mingw&lt;/i&gt; так не кажется, попытаюсь завтра побороть.&lt;/p&gt;
</description>
</item>

<item>
<title>Си++: форматированный вывод</title>
<guid isPermaLink="false">119170</guid>
<link>https://bolknote.ru/all/si-formatirovanny-vyvod/</link>
<pubDate>Sat, 06 May 2023 13:50:05 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/si-formatirovanny-vyvod/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Си++, похоже, язык для воспитания героев — создаём трудности на ровном месте и начинаем их преодолевать. В моём случае началось всё с разумной, как мне до сих пор кажется, идеи — заменить сишные безобразные строки &lt;tt&gt;char *&lt;/tt&gt; на прекрасный класс &lt;tt&gt;std::string&lt;/tt&gt; из Си++.&lt;/p&gt;
&lt;p&gt;В процессе в комментариях мне написали, что вместо него надо использовать &lt;tt&gt;std::string_view&lt;/tt&gt;, чтобы избежать копирования. Так я узнал, что за строки в Си++ отвечают не один класс, а четыре — есть ещё базовые классы, с приставкой &lt;tt&gt;base&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Заодно пришлось перейти на стандарт 2017 года, так как до строк с семантикой перемещения додумались только недавно.&lt;/p&gt;
&lt;p&gt;Всё шло хорошо, пока я не дошёл до форматирования текста. В Си этим занимается функция &lt;tt&gt;printf&lt;/tt&gt;, а Си++ есть метод &lt;tt&gt;std::format&lt;/tt&gt;, но вот беда — он появился только в стандарте 2020 года и его ещё нет ни в одном из компиляторов, которые есть у меня под рукой.&lt;/p&gt;
&lt;p&gt;Пошёл на поклон к ЧатГПТ, который выдал мне такую обёртку:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;template&amp;lt;typename... Args&amp;gt;
std::string string_format(const std::string format, Args... args) {
    int size_s = std::snprintf(nullptr, 0, format.data(), args ...) + 1; // Extra space for &amp;#039;\0&amp;#039;
    if (size_s &amp;lt;= 0) {
        throw std::runtime_error(&amp;quot;Error during formatting.&amp;quot;);
    }

    auto size = static_cast&amp;lt;size_t&amp;gt;( size_s );
    std::unique_ptr&amp;lt;char[]&amp;gt; buf(new char[size]);
    std::snprintf(buf.get(), size, format.data(), args ...);
    return {buf.get(), buf.get() + size - 1}; // We don&amp;#039;t want the &amp;#039;\0&amp;#039; inside
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Это так называемый «шаблонная функция». Насколько я пока понимаю принцип, компилятор смотрит с каким типами параметров вызывается эта функция, и делает их столько штук, сколько есть комбинаций вызовов.&lt;/p&gt;
&lt;p&gt;Так как файлы с кодом друг друга не видят, чтобы шаблонная функция «знала» с какими параметрами её вызывают, её надо помещать в заголовочный файл (🤦🏻‍♂️), либо указать в коде все необходимые прототипы вручную (🤦🏻‍♂️🤦🏻‍♂️🤦🏻‍♂️).&lt;/p&gt;
&lt;p&gt;И хотя я осознаю, что со своим уставом в чужой монастырь не лезут, первое мне кажется противоестественным, а второе — неудобным.&lt;/p&gt;
&lt;p&gt;На этом этапе я выяснил, что мой компилятор под «Виндоуз» ничего не знает про &lt;tt&gt;std::string_view&lt;/tt&gt;, а компилятор под «Мак» не может скомпилировать код выше вот с такой прекрасной ошибкой:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;comm/../utils.hpp:30:60: error: cannot pass object of non-trivial type &amp;#039;std::string&amp;#039; through variadic function; call will abort at runtime [-Wnon-pod-varargs]
    int size_s = std::snprintf(nullptr, 0, format.c_str(), std::forward&amp;lt;Args&amp;gt;(args)...) + 1;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Мне бы хотелось, чтобы код собирался под оба компилятора, поэтому я снова пошёл к ЧатГПТ и вернулся вот с таким прекрасным кодом:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;template&amp;lt;typename... Args&amp;gt;
std::string string_format(const std::string&amp;amp; format, Args&amp;amp;&amp;amp;... args) {
    auto size_s = std::snprintf(nullptr, 0, format.c_str(), 
                                 std::decay_t&amp;lt;Args&amp;gt;(args).c_str()...) + 1; // Extra space for &amp;#039;\0&amp;#039;
    if (size_s &amp;lt;= 0) {
        throw std::runtime_error(&amp;quot;Error during formatting.&amp;quot;);
    }

    auto size = static_cast&amp;lt;size_t&amp;gt;( size_s );
    std::unique_ptr&amp;lt;char[]&amp;gt; buf(new char[size]);
    std::snprintf(buf.get(), size, format.c_str(), 
                  std::decay_t&amp;lt;Args&amp;gt;(args).c_str()...);
    return {buf.get(), buf.get() + size - 1}; // We don&amp;#039;t want the &amp;#039;\0&amp;#039; inside
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Тут происходит какое-то чёрное кодунство в котором я ещё не разобрался. Но главное, что код заработал. Правда опять только под одним компилятором, второму не понравилось следующее:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;comm/../utils.hpp:32:58: error: request for member &amp;#039;c_str&amp;#039; in &amp;#039;args#0&amp;#039;, which is of non-class type &amp;#039;std::decay_t&amp;lt;char*&amp;gt;&amp;#039; {aka &amp;#039;char*&amp;#039;}
   std::decay_t&amp;lt;Args&amp;gt;(args).c_str()...) + 1;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;К счастью, решилось это просто — надо было всего лишь убрать &lt;tt&gt;.c_str()&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;По пути там пришлось решить ещё пару забавных мелочей, но они недостаточно отложились в памяти, чтобы я их мог воспроизвести без опасения в чём-то соврать.&lt;/p&gt;
&lt;p&gt;Теперь я понимаю за что программистам на Си++ платят такие деньги — это доплата за нервную работу.&lt;/p&gt;
</description>
</item>

<item>
<title>Бесплатный CLion?</title>
<guid isPermaLink="false">119122</guid>
<link>https://bolknote.ru/all/besplatny-clion/</link>
<pubDate>Thu, 04 May 2023 21:41:20 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/besplatny-clion/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Два дня до момента, когда моя среда разработки, где я мучаю Си++, превратится в тыкву. С преподавательской лицензией &lt;a href="https://bolknote.ru/all/gopnik-2-demotivirovalsya/"&gt;меня обломали&lt;/a&gt;, попробую другой путь — податься на бесплатную лицензию как бесплатный проект.&lt;/p&gt;
&lt;p&gt;Казалось бы дело в шляпе, но там надо показать регулярные коммиты за три месяца, а у меня пока ещё и месяц не прошёл. Но я придумал план, надёжный, как швейцарские часы, — два месяца рефакторинга. Буду перетаскивать очевидные сишные части на Си++. Начал со строк — переписываю сишные указатели на нормальный &lt;tt&gt;std::string&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Придётся, видимо, пока взять в качестве редактора &lt;i&gt;VSCode&lt;/i&gt;, вот только он не &lt;i&gt;IDE&lt;/i&gt;. Ну а какой выбор? В процессе знакомлюсь с тем, что умеет Си++. Смотрите какая прелесть:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;std::ostream &amp;amp;operator&amp;lt;&amp;lt;(std::ostream &amp;amp;os, const Colors &amp;amp;color) {
    static const std::map &amp;lt;Colors, std::string&amp;gt; colorNames = {
            {RESET,   &amp;quot;39;49m&amp;quot;},
            {BLUE,    &amp;quot;01;34m&amp;quot;},
            {GREEN,   &amp;quot;01;32m&amp;quot;},
            {CYAN,    &amp;quot;01;36m&amp;quot;},
            {RED,     &amp;quot;01;31m&amp;quot;},
            {MAGENTA, &amp;quot;01;35m&amp;quot;},
            {YELLOW,  &amp;quot;01;33m&amp;quot;},
            {WHITE,   &amp;quot;01;37m&amp;quot;},
            {BLACK,   &amp;quot;01;30m&amp;quot;},
    };

    os &amp;lt;&amp;lt; &amp;quot;\033[&amp;quot; &amp;lt;&amp;lt; colorNames.at(color);
    return os;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В Си это была большая функция с оператором &lt;tt&gt;switch&lt;/tt&gt;, которая выводила на экран последовательности для переключения цвета, её надо было вызывать отдельно каждый раз. На Си++ всё удобнее:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;std::cout &amp;lt;&amp;lt; YELLOW &amp;lt;&amp;lt; mess[2] &amp;lt;&amp;lt; std::flush;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Рраз и строка жёлтая. &lt;tt&gt;YELLOW&lt;/tt&gt; тут у меня — значение перечисляемого типа &lt;tt&gt;Colors&lt;/tt&gt;.&lt;/p&gt;
</description>
</item>

<item>
<title>«Гопник-2»: переход на нормальный Си++11</title>
<guid isPermaLink="false">118684</guid>
<link>https://bolknote.ru/all/gopnik-2-perehod-na-normalny-si-11/</link>
<pubDate>Mon, 24 Apr 2023 00:35:01 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/gopnik-2-perehod-na-normalny-si-11/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Как я &lt;a href="https://bolknote.ru/all/gopnik-2-raznye-mingw/"&gt;писал прежде&lt;/a&gt;, когда я адаптировал «Гопника-2» для запуска под «Виндоузом», столкнулся с тем, что не все тамошние компиляторы игру собирали. Не хватало двух функций — &lt;tt&gt;strdup&lt;/tt&gt; и &lt;tt&gt;_fileno&lt;/tt&gt;. Проблема решилось переключением компилятора на стандарт &lt;tt&gt;gnu++11&lt;/tt&gt;, но меня это беспокоило — вдруг найдётся компилятор, который его не поддерживает.&lt;/p&gt;
&lt;p&gt;Тут у нас в Татарстане выдались длинные выходные, — в праздник «Ураза-байрам» у нас выходной, я решил этим воспользоваться и поковырять эту тему подробнее.&lt;/p&gt;
&lt;p&gt;Вызов &lt;tt&gt;_fileno&lt;/tt&gt; у меня использовался для получения номера дескриптора входного потока, так что тут всё решилось просто, — для этого есть специальная константа &lt;tt&gt;STDIN_FILENO&lt;/tt&gt;. А вот с &lt;tt&gt;strdup&lt;/tt&gt; пришлось повозиться.&lt;/p&gt;
&lt;p&gt;Сначала я, разумеется, сделал свою реализацию — там всего-то три строки и заменил все вызовы на неё. Но мне показалось, что это слишком простое решение. А когда я программирую для души, мне хочется либо чему-то поучиться, либо сделать всё позамороченнее.&lt;/p&gt;
&lt;p&gt;Первым делом пошёл на поклон к «ЧатГПТ», спросил совета. Советы не заработали, но дали направление мысли.&lt;/p&gt;
&lt;p&gt;Первая мысль была забахать макрос, который заменял бы собой &lt;tt&gt;strdup&lt;/tt&gt; в проблемном компиляторе, а остальные не трогал. Тут надо сказать, что под «Виндой» далеко не во всех наборах утилит компиляторы не содержат функцию &lt;tt&gt;strdup&lt;/tt&gt;, например в &lt;tt&gt;msys2&lt;/tt&gt; она есть.&lt;/p&gt;
&lt;p&gt;Мне хотелось как-то отличать между собой обычный &lt;tt&gt;mingw&lt;/tt&gt; без &lt;tt&gt;strdup&lt;/tt&gt; от того, который внутри &lt;tt&gt;msys2&lt;/tt&gt;. «ЧатГПТ» тут не помог, хоть и подсунул несколько макросов на пробу, которых в действительности не существует.&lt;/p&gt;
&lt;p&gt;Пришлось пошарить по исходникам. Оказалось, есть ряд макросов, которые присутствуют в &lt;tt&gt;msys2&lt;/tt&gt;, но отсутствуют в &lt;tt&gt;msys&lt;/tt&gt;. Из них я выбрал &lt;tt&gt; __MINGW64_VERSION_MAJOR&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;#if defined(__MINGW32__) &amp;amp;&amp;amp; !defined(__MINGW64_VERSION_MAJOR)
#define strdup(s) (__extension__({ const char* __s = (s); size_t __l = strlen(__s) + 1; char* __d = (char*)malloc(__l);\
__d ? (char*)memcpy(__d, __s, __l) : nullptr; }))
#endif&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Тут используется расширение, которое позволяет писать многострочные макросы. Хотя этот вариант мне и нравится, но опять используется не нормальный Си++, а расширение компилятора.&lt;/p&gt;
&lt;p&gt;Вторая мысль, на которую меня навела нейросеть — использовать слабые символы языка Си++. Это совершенно новая для меня штука, поэтому нужно небольшое пояснение. Прежде всего для меня же, чтобы я в будущем не забыл что это вообще такое.&lt;/p&gt;
&lt;p&gt;Если упрощать, то символы — это экспортируемые именованные сущности. Те, что какой-то модуль может отдать во внешнее пользование. Если символ «сильный», то его имя никто не может занять, такой код просто не соберётся — компилятор скажет, что существует два символа с одним именем, а если он «слабый», то его можно заменить.&lt;/p&gt;
&lt;p&gt;Слабые символы используются для библиотек, чтобы пользователь мог заменить некоторые сущности, если они его не устраивают.&lt;/p&gt;
&lt;p&gt;Если перевернуть ситуацию, и считать мой код библиотекой, а тот код, где должна быть определена &lt;tt&gt;strdup&lt;/tt&gt; основным, то всё должно получиться.&lt;/p&gt;
&lt;p&gt;«ЧатГПТ», к сожалению, помочь не смог, — сначала подсовывал нерабочий код, а потом зациклился в своих советах. Поэтому пришлось разбираться самостоятельно.&lt;/p&gt;
&lt;p&gt;Всё оказалось не так уж и сложно. Сначала в заголовочном файле определяем прототип функции:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;#ifdef __MINGW32__
char *strdup(const char *s1);
#endif&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Я его спрятал под условие, чтобы мой редактор перестал ругаться на избыточное определение, но всё работает и без этого.&lt;/p&gt;
&lt;p&gt;Потом в самом коде создаём слабый символ для &lt;tt&gt;strdup&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;#ifdef __MINGW32__
#pragma weak my_strdup
char *strdup(const char *src) {
    size_t len = strlen(src) + 1;
    char *s = (char *) malloc(len);
    return s == nullptr ? nullptr : (char *) memcpy(s, src, len);
}
#endif&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Слабый символ я определяю через директиву &lt;tt&gt;#pragma weak&lt;/tt&gt;, у которой надо указать имя слабого символа, причём оно должно отличаться от имени функции. Я пока не до конца понял зачем это нужно делать, но без этого не работает.&lt;/p&gt;
&lt;p&gt;Кстати, &lt;tt&gt;#pragma weak&lt;/tt&gt; тоже расширение, но оно легко заменяется на атрибут &lt;tt&gt;weak&lt;/tt&gt;, надо только будет изучить его синтаксис, я не успел этого сделать.&lt;/p&gt;
&lt;p&gt;На имя &lt;tt&gt;my_strdup&lt;/tt&gt; у меня ругается редактор — говорит, что слабый символ нигде не определён, поэтому я опять же засунул всё это в условную компиляцию.&lt;/p&gt;
&lt;p&gt;В выходные, как всегда, есть куча дел, кроме хобби, поэтому до конца я разобраться не успел и буду рад, если кто-то из читателей прояснит это место. Если нет, поищу на досуге информацию в интернете.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Дополнено&lt;/i&gt;: в итоге все ситуации я побороть не смог и откатился на самое простое решение со своей собственной реализацией &lt;tt&gt;strdup&lt;/tt&gt;.&lt;/p&gt;
</description>
</item>

<item>
<title>auto в Си и Си++</title>
<guid isPermaLink="false">118616</guid>
<link>https://bolknote.ru/all/auto-in-c-and-c-plus-plus/</link>
<pubDate>Fri, 21 Apr 2023 14:06:49 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/auto-in-c-and-c-plus-plus/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Из-за дикой перегруженности фичами мне никогда не нравился язык Си++. До увлечения игрой «&lt;a href="https://bolknote.ru/tags/gopnik2-game/"&gt;Гопник-2&lt;/a&gt;» никогда на нём не программировал, но нужда заставила. Тянет с ней повозиться, а она написана на смеси Си и Си++, правда с упором на Си.&lt;/p&gt;
&lt;p&gt;Несмотря на неприязнь к Си++, всё-таки не могу не отметить, что местами на нём программировать куда проще, чем на Си. К сожалению, для того чтобы использовать реально полезные вещи, — нормальные строки или управление памятью, пришлось бы в игре многое переписать, но какие-то мелочи выручают и без переписывания кода.&lt;/p&gt;
&lt;p&gt;Одна из таких мелочей — ключевое слово &lt;tt&gt;auto&lt;/tt&gt;. Оно есть и в Си, но значение у него &lt;a href="http://web.archive.org/web/20130927234242/http://itee.uq.edu.au/~comp2303/Leslie_C_ref/C/CONCEPT/storage_class.html"&gt;совершенно другое&lt;/a&gt;, в современном коде, как будто бы, его использовать негде.&lt;/p&gt;
&lt;p&gt;В Си++ оно означает автоматический вывод типа, вместо его явного указания. Клёвая штука, позволяет делать например такое (пример из кода «Гопника-2»):&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;auto old_mode = set_tty_special_mode();
// тут какой-то код
restore_tty_mode(old_mode);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Фишка тут в том, что у &lt;tt&gt;set_tty_special_mode&lt;/tt&gt; и &lt;tt&gt;restore_tty_mode&lt;/tt&gt; две реализации — под «Виндоуз» своя. Эти две реализации работают с разными типами, под «Виндоуз» там &lt;tt&gt;DWORD&lt;/tt&gt;, в остальных случаях — структура &lt;tt&gt;termios&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;В Си было бы что-то вроде:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;#ifdef __MINGW32__
#typedef DWORD terminal_mode
#else
#typedef struct termios terminal_mode
#endif

terminal_mode old_mode = set_tty_special_mode();
// тут какой-то код
restore_tty_mode(old_mode);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;А в Си++ можно просто поставить &lt;tt&gt;auto&lt;/tt&gt; и обойтись без шаблонного кода. Очень хочется иметь такую клёвую примочку и в Си.&lt;/p&gt;
</description>
</item>

<item>
<title>Программируем с GPT</title>
<guid isPermaLink="false">118297</guid>
<link>https://bolknote.ru/all/programmiruem-s-gpt/</link>
<pubDate>Wed, 12 Apr 2023 15:53:44 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/programmiruem-s-gpt/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Мне всё-таки кажется, что в интернете достаточно примеров как замечательно нейросети справляются с программированием, надо восстанавливать баланс. Свежий пример из моей практики.&lt;/p&gt;
&lt;p&gt;Нужно было переписать вот такой код с «Пайтона» на «Си++»:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="python"&gt;{72: 65, 80: 66}.get(value, 0)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Что тут происходит? Если &lt;tt&gt;value&lt;/tt&gt; равно 72, вернуть 65, если 80, то 66, иначе ноль. Нужно мне это, если вкратце, для преобразования виндовых кодов в линуксовые.&lt;/p&gt;
&lt;p&gt;Так как Си++ я не знаю, описал на Пайтоне — так быстрее и проще показать, что код мне нужен компактный — хочется не городить &lt;tt&gt;switch&lt;/tt&gt;, а добавлять новое правило как можно проще.&lt;/p&gt;
&lt;p&gt;Вот что мне сгенерировал &lt;i&gt;ChatGPT-4&lt;/i&gt;:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;int value = 72;
std::map&amp;lt;int, int&amp;gt; mymap = {{72, 65}, {80, 66}};
int result = mymap.count(value) ? mymap[value] : 0;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;После консультации с живыми людьми, выяснилось, что плохо тут примерно всё.&lt;/p&gt;
&lt;p&gt;Во-первых, вместо &lt;tt&gt;map&lt;/tt&gt; надо использовать &lt;tt&gt;unordered_map&lt;/tt&gt;, сложность поиска по первой структуре логарифмическая, по второй — константная в среднем.&lt;br /&gt;
Во-вторых, в этом коде надо использовать &lt;tt&gt;find&lt;/tt&gt;, а не &lt;tt&gt;count&lt;/tt&gt;, так как &lt;tt&gt;find&lt;/tt&gt; остановится после первого совпадения (что нам и надо), а &lt;tt&gt;count&lt;/tt&gt; — нет, продолжая тратить ресурсы.&lt;br /&gt;
В-третьих, &lt;tt&gt;map&lt;/tt&gt; создаётся в этом примере каждый раз вместо одного. Хороший программист так это не оставит.&lt;/p&gt;
&lt;p&gt;В итоге, код стал выглядеть следующим образом:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="cpp"&gt;const static std::unordered_map&amp;lt;int, int&amp;gt; win2lin = {{72, 65}, {80, 66}};

auto it = win2lin.find(_getch());
ch = it == win2lin.end() ? 0 : it-&amp;gt;second;&lt;/code&gt;&lt;/pre&gt;</description>
</item>

<item>
<title>«Гопник-2»: разные mingw</title>
<guid isPermaLink="false">118045</guid>
<link>https://bolknote.ru/all/gopnik-2-raznye-mingw/</link>
<pubDate>Sat, 08 Apr 2023 17:51:32 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/gopnik-2-raznye-mingw/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Надо по-быстрому дописать посты про портирования игры на «Виндоуз», пока свежо в памяти. Так что продолжу.&lt;/p&gt;
&lt;p&gt;Сильнее всего меня удивило в процессе, что поведение &lt;tt&gt;mingw&lt;/tt&gt;, — инструментария для компиляции приложений под «Виндоуз», различается под разными операционными системами.&lt;/p&gt;
&lt;p&gt;Поскольку мне не хотелось заморачиваться с установкой софта на виртуальную машину, я развернул &lt;tt&gt;mingw&lt;/tt&gt; у себя под «Маком» и внёс правки, чтобы всё благополучно компилировалось именно на этой ОС.&lt;/p&gt;
&lt;p&gt;Запустив получившееся на первой попавшейся виндовой виртуалке, я успокоился. Но &lt;a href="https://github.com/bolknote/gopnik2/issues/4"&gt;оказалось&lt;/a&gt; этого недостаточно — под самой «Виндоуз» приложение не собиралось!&lt;/p&gt;
&lt;p&gt;Во-первых, под «Виндой» отсутствовала функция &lt;tt&gt;strdup&lt;/tt&gt;, интернет ничего не подсказал, но я случайно решил эту проблему, установив стандарт языка в &lt;i&gt;GNU C++11&lt;/i&gt;: &lt;tt&gt;-std=gnu++11&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Во-вторых, почему отсутствовали-то ряд важных констант. Cледуя совету на «Стековерфлоу», я просто определил их нужными значениями.&lt;/p&gt;
&lt;p&gt;В-третьих, функцию &lt;tt&gt;usleep&lt;/tt&gt; пришлось заменить на &lt;tt&gt;Sleep&lt;/tt&gt; из &lt;tt&gt;windows.h&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;После этих правок игра начала собираться под «Виндой» тоже.&lt;/p&gt;
&lt;p&gt;Недавно прочитал в одной из статей на Хабре, что «язык Си++ достаточно сложен, чтобы позволить нам писать на нём просто», как же это верно! Неожиданно много времени занимает борьба с какими-то вещами, которые, как мне кажется, должны просто работать.&lt;/p&gt;
</description>
</item>


</channel>
</rss>