{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Блоги: заметки с тегом cpp",
    "_rss_description": "Автоматически собираемая лента заметок, написанных в блогах на Эгее",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": false,
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/blogengine.me\/blogs\/tags\/cpp\/",
    "feed_url": "https:\/\/blogengine.me\/blogs\/tags\/cpp\/json\/",
    "icon": false,
    "authors": [
        {
            "name": "Илья Бирман",
            "url": "https:\/\/blogengine.me\/blogs\/",
            "avatar": false
        }
    ],
    "items": [
        {
            "id": "119190",
            "url": "https:\/\/bolknote.ru\/all\/si-formatirovanny-vyvod-prodolzhenie\/",
            "title": "Си++: форматированный вывод (продолжение)",
            "content_html": "<p>Очень раздражает, что вместо того, чтобы писать прикладной код, я вынужден бороться с компиляторами, да не с одним, а с тремя, под разные операционные системы. Я как будто пытаюсь писать не на одном языке, а сразу на трёх, похожих, но не полностью.<\/p>\n<p>Мои приключения c <a href=\"https:\/\/bolknote.ru\/all\/si-formatirovanny-vyvod\/\">форматированным выводом<\/a> в Си++ до сих пор не закончились, оказалось, что последний вариант обёртки над <tt>std::snprintf<\/tt> в одном из компиляторов не собирается с одним из видов аргументов, пришлось его обернуть в <tt>std::cref<\/tt>.<\/p>\n<p>Умные люди в комментариях советуют перейти на внешнюю библиотеку <a href=\"https:\/\/github.com\/fmtlib\/fmt\"><i>fmt<\/i><\/a> и я уже сделал подход к снаряду, но под <i>mingw<\/i> у меня сборка пока не заработала. Завтра попытаюсь ещё раз — хочу подключить библиотеку подмодулем к своему репозиторию встроить компиляцию в процесс сборки своего проекта. Мне кажется, что я делаю всё правильно, а вот <i>mingw<\/i> так не кажется, попытаюсь завтра побороть.<\/p>\n",
            "date_published": "2023-05-07T23:43:13+05:00",
            "date_modified": "2023-05-07T23:42:51+05:00",
            "tags": [
                "cpp",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sun, 07 May 2023 23:43:13 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "119190",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "119170",
            "url": "https:\/\/bolknote.ru\/all\/si-formatirovanny-vyvod\/",
            "title": "Си++: форматированный вывод",
            "content_html": "<p>Си++, похоже, язык для воспитания героев — создаём трудности на ровном месте и начинаем их преодолевать. В моём случае началось всё с разумной, как мне до сих пор кажется, идеи — заменить сишные безобразные строки <tt>char *<\/tt> на прекрасный класс <tt>std::string<\/tt> из Си++.<\/p>\n<p>В процессе в комментариях мне написали, что вместо него надо использовать <tt>std::string_view<\/tt>, чтобы избежать копирования. Так я узнал, что за строки в Си++ отвечают не один класс, а четыре — есть ещё базовые классы, с приставкой <tt>base<\/tt>.<\/p>\n<p>Заодно пришлось перейти на стандарт 2017 года, так как до строк с семантикой перемещения додумались только недавно.<\/p>\n<p>Всё шло хорошо, пока я не дошёл до форматирования текста. В Си этим занимается функция <tt>printf<\/tt>, а Си++ есть метод <tt>std::format<\/tt>, но вот беда — он появился только в стандарте 2020 года и его ещё нет ни в одном из компиляторов, которые есть у меня под рукой.<\/p>\n<p>Пошёл на поклон к ЧатГПТ, который выдал мне такую обёртку:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">template&lt;typename... Args&gt;\r\nstd::string string_format(const std::string format, Args... args) {\r\n    int size_s = std::snprintf(nullptr, 0, format.data(), args ...) + 1; \/\/ Extra space for &#039;\\0&#039;\r\n    if (size_s &lt;= 0) {\r\n        throw std::runtime_error(&quot;Error during formatting.&quot;);\r\n    }\r\n\r\n    auto size = static_cast&lt;size_t&gt;( size_s );\r\n    std::unique_ptr&lt;char[]&gt; buf(new char[size]);\r\n    std::snprintf(buf.get(), size, format.data(), args ...);\r\n    return {buf.get(), buf.get() + size - 1}; \/\/ We don&#039;t want the &#039;\\0&#039; inside\r\n}<\/code><\/pre><p>Это так называемый «шаблонная функция». Насколько я пока понимаю принцип, компилятор смотрит с каким типами параметров вызывается эта функция, и делает их столько штук, сколько есть комбинаций вызовов.<\/p>\n<p>Так как файлы с кодом друг друга не видят, чтобы шаблонная функция «знала» с какими параметрами её вызывают, её надо помещать в заголовочный файл (🤦🏻‍♂️), либо указать в коде все необходимые прототипы вручную (🤦🏻‍♂️🤦🏻‍♂️🤦🏻‍♂️).<\/p>\n<p>И хотя я осознаю, что со своим уставом в чужой монастырь не лезут, первое мне кажется противоестественным, а второе — неудобным.<\/p>\n<p>На этом этапе я выяснил, что мой компилятор под «Виндоуз» ничего не знает про <tt>std::string_view<\/tt>, а компилятор под «Мак» не может скомпилировать код выше вот с такой прекрасной ошибкой:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">comm\/..\/utils.hpp:30:60: error: cannot pass object of non-trivial type &#039;std::string&#039; through variadic function; call will abort at runtime [-Wnon-pod-varargs]\r\n    int size_s = std::snprintf(nullptr, 0, format.c_str(), std::forward&lt;Args&gt;(args)...) + 1;<\/code><\/pre><p>Мне бы хотелось, чтобы код собирался под оба компилятора, поэтому я снова пошёл к ЧатГПТ и вернулся вот с таким прекрасным кодом:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">template&lt;typename... Args&gt;\r\nstd::string string_format(const std::string&amp; format, Args&amp;&amp;... args) {\r\n    auto size_s = std::snprintf(nullptr, 0, format.c_str(), \r\n                                 std::decay_t&lt;Args&gt;(args).c_str()...) + 1; \/\/ Extra space for &#039;\\0&#039;\r\n    if (size_s &lt;= 0) {\r\n        throw std::runtime_error(&quot;Error during formatting.&quot;);\r\n    }\r\n\r\n    auto size = static_cast&lt;size_t&gt;( size_s );\r\n    std::unique_ptr&lt;char[]&gt; buf(new char[size]);\r\n    std::snprintf(buf.get(), size, format.c_str(), \r\n                  std::decay_t&lt;Args&gt;(args).c_str()...);\r\n    return {buf.get(), buf.get() + size - 1}; \/\/ We don&#039;t want the &#039;\\0&#039; inside\r\n}<\/code><\/pre><p>Тут происходит какое-то чёрное кодунство в котором я ещё не разобрался. Но главное, что код заработал. Правда опять только под одним компилятором, второму не понравилось следующее:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">comm\/..\/utils.hpp:32:58: error: request for member &#039;c_str&#039; in &#039;args#0&#039;, which is of non-class type &#039;std::decay_t&lt;char*&gt;&#039; {aka &#039;char*&#039;}\r\n   std::decay_t&lt;Args&gt;(args).c_str()...) + 1;<\/code><\/pre><p>К счастью, решилось это просто — надо было всего лишь убрать <tt>.c_str()<\/tt>.<\/p>\n<p>По пути там пришлось решить ещё пару забавных мелочей, но они недостаточно отложились в памяти, чтобы я их мог воспроизвести без опасения в чём-то соврать.<\/p>\n<p>Теперь я понимаю за что программистам на Си++ платят такие деньги — это доплата за нервную работу.<\/p>\n",
            "date_published": "2023-05-06T13:50:05+05:00",
            "date_modified": "2023-05-06T13:56:54+05:00",
            "tags": [
                "cpp",
                "игра «Гопник-2»",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sat, 06 May 2023 13:50:05 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "119170",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "119122",
            "url": "https:\/\/bolknote.ru\/all\/besplatny-clion\/",
            "title": "Бесплатный CLion?",
            "content_html": "<p>Два дня до момента, когда моя среда разработки, где я мучаю Си++, превратится в тыкву. С преподавательской лицензией <a href=\"https:\/\/bolknote.ru\/all\/gopnik-2-demotivirovalsya\/\">меня обломали<\/a>, попробую другой путь — податься на бесплатную лицензию как бесплатный проект.<\/p>\n<p>Казалось бы дело в шляпе, но там надо показать регулярные коммиты за три месяца, а у меня пока ещё и месяц не прошёл. Но я придумал план, надёжный, как швейцарские часы, — два месяца рефакторинга. Буду перетаскивать очевидные сишные части на Си++. Начал со строк — переписываю сишные указатели на нормальный <tt>std::string<\/tt>.<\/p>\n<p>Придётся, видимо, пока взять в качестве редактора <i>VSCode<\/i>, вот только он не <i>IDE<\/i>. Ну а какой выбор? В процессе знакомлюсь с тем, что умеет Си++. Смотрите какая прелесть:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">std::ostream &amp;operator&lt;&lt;(std::ostream &amp;os, const Colors &amp;color) {\r\n    static const std::map &lt;Colors, std::string&gt; colorNames = {\r\n            {RESET,   &quot;39;49m&quot;},\r\n            {BLUE,    &quot;01;34m&quot;},\r\n            {GREEN,   &quot;01;32m&quot;},\r\n            {CYAN,    &quot;01;36m&quot;},\r\n            {RED,     &quot;01;31m&quot;},\r\n            {MAGENTA, &quot;01;35m&quot;},\r\n            {YELLOW,  &quot;01;33m&quot;},\r\n            {WHITE,   &quot;01;37m&quot;},\r\n            {BLACK,   &quot;01;30m&quot;},\r\n    };\r\n\r\n    os &lt;&lt; &quot;\\033[&quot; &lt;&lt; colorNames.at(color);\r\n    return os;\r\n}<\/code><\/pre><p>В Си это была большая функция с оператором <tt>switch<\/tt>, которая выводила на экран последовательности для переключения цвета, её надо было вызывать отдельно каждый раз. На Си++ всё удобнее:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">std::cout &lt;&lt; YELLOW &lt;&lt; mess[2] &lt;&lt; std::flush;<\/code><\/pre><p>Рраз и строка жёлтая. <tt>YELLOW<\/tt> тут у меня — значение перечисляемого типа <tt>Colors<\/tt>.<\/p>\n",
            "date_published": "2023-05-04T21:41:20+05:00",
            "date_modified": "2023-05-04T21:44:30+05:00",
            "tags": [
                "cpp",
                "игра «Гопник-2»"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Thu, 04 May 2023 21:41:20 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "119122",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "118684",
            "url": "https:\/\/bolknote.ru\/all\/gopnik-2-perehod-na-normalny-si-11\/",
            "title": "«Гопник-2»: переход на нормальный Си++11",
            "content_html": "<p>Как я <a href=\"https:\/\/bolknote.ru\/all\/gopnik-2-raznye-mingw\/\">писал прежде<\/a>, когда я адаптировал «Гопника-2» для запуска под «Виндоузом», столкнулся с тем, что не все тамошние компиляторы игру собирали. Не хватало двух функций — <tt>strdup<\/tt> и <tt>_fileno<\/tt>. Проблема решилось переключением компилятора на стандарт <tt>gnu++11<\/tt>, но меня это беспокоило — вдруг найдётся компилятор, который его не поддерживает.<\/p>\n<p>Тут у нас в Татарстане выдались длинные выходные, — в праздник «Ураза-байрам» у нас выходной, я решил этим воспользоваться и поковырять эту тему подробнее.<\/p>\n<p>Вызов <tt>_fileno<\/tt> у меня использовался для получения номера дескриптора входного потока, так что тут всё решилось просто, — для этого есть специальная константа <tt>STDIN_FILENO<\/tt>. А вот с <tt>strdup<\/tt> пришлось повозиться.<\/p>\n<p>Сначала я, разумеется, сделал свою реализацию — там всего-то три строки и заменил все вызовы на неё. Но мне показалось, что это слишком простое решение. А когда я программирую для души, мне хочется либо чему-то поучиться, либо сделать всё позамороченнее.<\/p>\n<p>Первым делом пошёл на поклон к «ЧатГПТ», спросил совета. Советы не заработали, но дали направление мысли.<\/p>\n<p>Первая мысль была забахать макрос, который заменял бы собой <tt>strdup<\/tt> в проблемном компиляторе, а остальные не трогал. Тут надо сказать, что под «Виндой» далеко не во всех наборах утилит компиляторы не содержат функцию <tt>strdup<\/tt>, например в <tt>msys2<\/tt> она есть.<\/p>\n<p>Мне хотелось как-то отличать между собой обычный <tt>mingw<\/tt> без <tt>strdup<\/tt> от того, который внутри <tt>msys2<\/tt>. «ЧатГПТ» тут не помог, хоть и подсунул несколько макросов на пробу, которых в действительности не существует.<\/p>\n<p>Пришлось пошарить по исходникам. Оказалось, есть ряд макросов, которые присутствуют в <tt>msys2<\/tt>, но отсутствуют в <tt>msys<\/tt>. Из них я выбрал <tt> __MINGW64_VERSION_MAJOR<\/tt>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">#if defined(__MINGW32__) &amp;&amp; !defined(__MINGW64_VERSION_MAJOR)\r\n#define strdup(s) (__extension__({ const char* __s = (s); size_t __l = strlen(__s) + 1; char* __d = (char*)malloc(__l);\\\r\n__d ? (char*)memcpy(__d, __s, __l) : nullptr; }))\r\n#endif<\/code><\/pre><p>Тут используется расширение, которое позволяет писать многострочные макросы. Хотя этот вариант мне и нравится, но опять используется не нормальный Си++, а расширение компилятора.<\/p>\n<p>Вторая мысль, на которую меня навела нейросеть — использовать слабые символы языка Си++. Это совершенно новая для меня штука, поэтому нужно небольшое пояснение. Прежде всего для меня же, чтобы я в будущем не забыл что это вообще такое.<\/p>\n<p>Если упрощать, то символы — это экспортируемые именованные сущности. Те, что какой-то модуль может отдать во внешнее пользование. Если символ «сильный», то его имя никто не может занять, такой код просто не соберётся — компилятор скажет, что существует два символа с одним именем, а если он «слабый», то его можно заменить.<\/p>\n<p>Слабые символы используются для библиотек, чтобы пользователь мог заменить некоторые сущности, если они его не устраивают.<\/p>\n<p>Если перевернуть ситуацию, и считать мой код библиотекой, а тот код, где должна быть определена <tt>strdup<\/tt> основным, то всё должно получиться.<\/p>\n<p>«ЧатГПТ», к сожалению, помочь не смог, — сначала подсовывал нерабочий код, а потом зациклился в своих советах. Поэтому пришлось разбираться самостоятельно.<\/p>\n<p>Всё оказалось не так уж и сложно. Сначала в заголовочном файле определяем прототип функции:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">#ifdef __MINGW32__\r\nchar *strdup(const char *s1);\r\n#endif<\/code><\/pre><p>Я его спрятал под условие, чтобы мой редактор перестал ругаться на избыточное определение, но всё работает и без этого.<\/p>\n<p>Потом в самом коде создаём слабый символ для <tt>strdup<\/tt>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">#ifdef __MINGW32__\r\n#pragma weak my_strdup\r\nchar *strdup(const char *src) {\r\n    size_t len = strlen(src) + 1;\r\n    char *s = (char *) malloc(len);\r\n    return s == nullptr ? nullptr : (char *) memcpy(s, src, len);\r\n}\r\n#endif<\/code><\/pre><p>Слабый символ я определяю через директиву <tt>#pragma weak<\/tt>, у которой надо указать имя слабого символа, причём оно должно отличаться от имени функции. Я пока не до конца понял зачем это нужно делать, но без этого не работает.<\/p>\n<p>Кстати, <tt>#pragma weak<\/tt> тоже расширение, но оно легко заменяется на атрибут <tt>weak<\/tt>, надо только будет изучить его синтаксис, я не успел этого сделать.<\/p>\n<p>На имя <tt>my_strdup<\/tt> у меня ругается редактор — говорит, что слабый символ нигде не определён, поэтому я опять же засунул всё это в условную компиляцию.<\/p>\n<p>В выходные, как всегда, есть куча дел, кроме хобби, поэтому до конца я разобраться не успел и буду рад, если кто-то из читателей прояснит это место. Если нет, поищу на досуге информацию в интернете.<\/p>\n<p><i>Дополнено<\/i>: в итоге все ситуации я побороть не смог и откатился на самое простое решение со своей собственной реализацией <tt>strdup<\/tt>.<\/p>\n",
            "date_published": "2023-04-24T00:35:01+05:00",
            "date_modified": "2023-05-03T23:58:44+05:00",
            "tags": [
                "cpp",
                "gopnik",
                "игра «Гопник-2»",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Mon, 24 Apr 2023 00:35:01 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "118684",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "118616",
            "url": "https:\/\/bolknote.ru\/all\/auto-in-c-and-c-plus-plus\/",
            "title": "auto в Си и Си++",
            "content_html": "<p>Из-за дикой перегруженности фичами мне никогда не нравился язык Си++. До увлечения игрой «<a href=\"https:\/\/bolknote.ru\/tags\/gopnik2-game\/\">Гопник-2<\/a>» никогда на нём не программировал, но нужда заставила. Тянет с ней повозиться, а она написана на смеси Си и Си++, правда с упором на Си.<\/p>\n<p>Несмотря на неприязнь к Си++, всё-таки не могу не отметить, что местами на нём программировать куда проще, чем на Си. К сожалению, для того чтобы использовать реально полезные вещи, — нормальные строки или управление памятью, пришлось бы в игре многое переписать, но какие-то мелочи выручают и без переписывания кода.<\/p>\n<p>Одна из таких мелочей — ключевое слово <tt>auto<\/tt>. Оно есть и в Си, но значение у него <a href=\"http:\/\/web.archive.org\/web\/20130927234242\/http:\/\/itee.uq.edu.au\/~comp2303\/Leslie_C_ref\/C\/CONCEPT\/storage_class.html\">совершенно другое<\/a>, в современном коде, как будто бы, его использовать негде.<\/p>\n<p>В Си++ оно означает автоматический вывод типа, вместо его явного указания. Клёвая штука, позволяет делать например такое (пример из кода «Гопника-2»):<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">auto old_mode = set_tty_special_mode();\r\n\/\/ тут какой-то код\r\nrestore_tty_mode(old_mode);<\/code><\/pre><p>Фишка тут в том, что у <tt>set_tty_special_mode<\/tt> и <tt>restore_tty_mode<\/tt> две реализации — под «Виндоуз» своя. Эти две реализации работают с разными типами, под «Виндоуз» там <tt>DWORD<\/tt>, в остальных случаях — структура <tt>termios<\/tt>.<\/p>\n<p>В Си было бы что-то вроде:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">#ifdef __MINGW32__\r\n#typedef DWORD terminal_mode\r\n#else\r\n#typedef struct termios terminal_mode\r\n#endif\r\n\r\nterminal_mode old_mode = set_tty_special_mode();\r\n\/\/ тут какой-то код\r\nrestore_tty_mode(old_mode);<\/code><\/pre><p>А в Си++ можно просто поставить <tt>auto<\/tt> и обойтись без шаблонного кода. Очень хочется иметь такую клёвую примочку и в Си.<\/p>\n",
            "date_published": "2023-04-21T14:06:49+05:00",
            "date_modified": "2023-04-21T15:15:23+05:00",
            "tags": [
                "cpp",
                "программирование",
                "си"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Fri, 21 Apr 2023 14:06:49 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "118616",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "118297",
            "url": "https:\/\/bolknote.ru\/all\/programmiruem-s-gpt\/",
            "title": "Программируем с GPT",
            "content_html": "<p>Мне всё-таки кажется, что в интернете достаточно примеров как замечательно нейросети справляются с программированием, надо восстанавливать баланс. Свежий пример из моей практики.<\/p>\n<p>Нужно было переписать вот такой код с «Пайтона» на «Си++»:<\/p>\n<pre class=\"e2-text-code\"><code class=\"python\">{72: 65, 80: 66}.get(value, 0)<\/code><\/pre><p>Что тут происходит? Если <tt>value<\/tt> равно 72, вернуть 65, если 80, то 66, иначе ноль. Нужно мне это, если вкратце, для преобразования виндовых кодов в линуксовые.<\/p>\n<p>Так как Си++ я не знаю, описал на Пайтоне — так быстрее и проще показать, что код мне нужен компактный — хочется не городить <tt>switch<\/tt>, а добавлять новое правило как можно проще.<\/p>\n<p>Вот что мне сгенерировал <i>ChatGPT-4<\/i>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">int value = 72;\r\nstd::map&lt;int, int&gt; mymap = {{72, 65}, {80, 66}};\r\nint result = mymap.count(value) ? mymap[value] : 0;<\/code><\/pre><p>После консультации с живыми людьми, выяснилось, что плохо тут примерно всё.<\/p>\n<p>Во-первых, вместо <tt>map<\/tt> надо использовать <tt>unordered_map<\/tt>, сложность поиска по первой структуре логарифмическая, по второй — константная в среднем.<br \/>\nВо-вторых, в этом коде надо использовать <tt>find<\/tt>, а не <tt>count<\/tt>, так как <tt>find<\/tt> остановится после первого совпадения (что нам и надо), а <tt>count<\/tt> — нет, продолжая тратить ресурсы.<br \/>\nВ-третьих, <tt>map<\/tt> создаётся в этом примере каждый раз вместо одного. Хороший программист так это не оставит.<\/p>\n<p>В итоге, код стал выглядеть следующим образом:<\/p>\n<pre class=\"e2-text-code\"><code class=\"cpp\">const static std::unordered_map&lt;int, int&gt; win2lin = {{72, 65}, {80, 66}};\r\n\r\nauto it = win2lin.find(_getch());\r\nch = it == win2lin.end() ? 0 : it-&gt;second;<\/code><\/pre>",
            "date_published": "2023-04-12T15:53:44+05:00",
            "date_modified": "2023-04-12T17:13:22+05:00",
            "tags": [
                "chatGPT",
                "cpp",
                "ИИ"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Wed, 12 Apr 2023 15:53:44 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "118297",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "118045",
            "url": "https:\/\/bolknote.ru\/all\/gopnik-2-raznye-mingw\/",
            "title": "«Гопник-2»: разные mingw",
            "content_html": "<p>Надо по-быстрому дописать посты про портирования игры на «Виндоуз», пока свежо в памяти. Так что продолжу.<\/p>\n<p>Сильнее всего меня удивило в процессе, что поведение <tt>mingw<\/tt>, — инструментария для компиляции приложений под «Виндоуз», различается под разными операционными системами.<\/p>\n<p>Поскольку мне не хотелось заморачиваться с установкой софта на виртуальную машину, я развернул <tt>mingw<\/tt> у себя под «Маком» и внёс правки, чтобы всё благополучно компилировалось именно на этой ОС.<\/p>\n<p>Запустив получившееся на первой попавшейся виндовой виртуалке, я успокоился. Но <a href=\"https:\/\/github.com\/bolknote\/gopnik2\/issues\/4\">оказалось<\/a> этого недостаточно — под самой «Виндоуз» приложение не собиралось!<\/p>\n<p>Во-первых, под «Виндой» отсутствовала функция <tt>strdup<\/tt>, интернет ничего не подсказал, но я случайно решил эту проблему, установив стандарт языка в <i>GNU C++11<\/i>: <tt>-std=gnu++11<\/tt>.<\/p>\n<p>Во-вторых, почему отсутствовали-то ряд важных констант. Cледуя совету на «Стековерфлоу», я просто определил их нужными значениями.<\/p>\n<p>В-третьих, функцию <tt>usleep<\/tt> пришлось заменить на <tt>Sleep<\/tt> из <tt>windows.h<\/tt>.<\/p>\n<p>После этих правок игра начала собираться под «Виндой» тоже.<\/p>\n<p>Недавно прочитал в одной из статей на Хабре, что «язык Си++ достаточно сложен, чтобы позволить нам писать на нём просто», как же это верно! Неожиданно много времени занимает борьба с какими-то вещами, которые, как мне кажется, должны просто работать.<\/p>\n",
            "date_published": "2023-04-08T17:51:32+05:00",
            "date_modified": "2023-04-14T16:10:36+05:00",
            "tags": [
                "cpp",
                "gopnik",
                "игра «Гопник-2»",
                "программирование"
            ],
            "author": {
                "name": "Евгений Степанищев",
                "url": "https:\/\/bolknote.ru\/",
                "avatar": "https:\/\/bolknote.ru\/pictures\/userpic\/userpic@2x.jpg?1760600028"
            },
            "_date_published_rfc2822": "Sat, 08 Apr 2023 17:51:32 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "118045",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        }
    ],
    "_e2_version": 4079,
    "_e2_ua_string": "Aegea 11.0 (v4079e)"
}