Библиотека C/C++ разработчика | cpp, boost, qt
17.2K subscribers
2.19K photos
67 videos
16 files
4.55K links
Все самое полезное для плюсовика и сишника в одном канале.

Как запустить своего ии-агента: https://clc.to/tvpmDQ

По рекламе: @proglib_adv

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a5bac324c8ba6dcaa1ad17

#WXSSA
Download Telegram
🥳 Алгоритмы диапазонов: Свёртки (fold)

В прошлый раз модифицировали диапазоны — теперь сворачиваем их в одно значение. В C++23 появилось семейство fold_*, которое наконец заменяет std::accumulate и аккуратно выводит типы.


🍰 ranges::fold_left — свёртка слева

std::vector<int> v = {1, 2, 3, 4, 5};
int sum = std::ranges::fold_left(v, 0, std::plus{}); // 15
int product = std::ranges::fold_left(v, 1, std::multiplies{}); // 120


Левоассоциативная свёртка: аккумулятор — левый аргумент операции, элемент — правый. По шагам это (((( 0+1 )+2 )+3 )+4 )+5. Начальное значение задаёте сами.


🥨 ranges::fold_left_first — первый элемент как начало

std::vector<int> v = {3, 1, 4, 1, 5};
auto max_val = std::ranges::fold_left_first(v, [](int a, int b){
return std::max(a, b);
});
// max_val == std::optional<int>{5}


То же самое, но начальным значением берётся первый элемент диапазона — отдельный init не нужен. Удобно для max/min, где придумывать «нейтральный» элемент неловко (Для готовых max/min, конечно, есть ranges::max — fold_left_first интересен произвольной операцией).

❗️ Возвращает std::optional: у пустого диапазона нет первого элемента, поэтому на пустом входе придёт std::nullopt. Не забудьте проверить перед разыменованием.


🥖 ranges::fold_right — свёртка справа

std::vector<int> v = {1, 2, 3};
int r = std::ranges::fold_right(v, 0, std::minus{});
// 1 - (2 - (3 - 0)) == 2
int l = std::ranges::fold_left(v, 0, std::minus{});
// ((0 - 1) - 2) - 3 == -6


Идёт с правого конца: result = f(1, f(2, f(3, 0))). Для коммутативных операций (plus, multiplies) результат совпадёт с fold_left, а для некоммутативных — нет, как видно по вычитанию.

❗️ У fold_right порядок аргументов операции зеркальный: вызывается f(элемент, аккумулятор), то есть элемент идёт первым, а не вторым. Для своих лямбд это легко перепутать.


🥯 ranges::fold_right_last — последний элемент как начало

std::vector<int> v = {1, 2, 3};
auto res = std::ranges::fold_right_last(v, std::minus{});
// 1 - (2 - 3) == 2, внутри std::optional<int>{2}


Зеркало fold_left_first: начальным значением берётся последний элемент, результат — тоже std::optional с тем же поведением на пустом диапазоне.


🧇 ranges::fold_left_with_iter — результат и итератор

std::vector<int> v = {1, 2, 3, 4, 5};
auto [in, value] = std::ranges::fold_left_with_iter(v, 0, std::plus{});
// value == 15
// in == v.end()


Возвращает не просто значение, а структуру с полями in (итератор конца обработки) и value. Полезно, когда после свёртки нужно знать, где именно остановились — например, при работе с подсчётами в потоке.


❗️ Несколько подводных камней

• Главное отличие от accumulate — в том, как выводится тип накопления. У accumulate тип аккумулятора равен типу init, поэтому std::accumulate(vd.begin(), vd.end(), 0) на векторе double молча копит в int и теряет дробную часть. А fold_left выводит тип аккумулятора из РЕЗУЛЬТАТА операции (U = decay_t<invoke_result_t<F&, T, range_reference_t<R>>>), и здесь int-ный ноль на векторе double уже ничего не теряет: plus(int, double) даёт double, и всё копится в double.

std::vector<double> vd = {1.5, 2.5, 3.0};
auto s = std::ranges::fold_left(vd, 0, std::plus{});
// s == 7.0, а НЕ 6 — тип s выведен как double
// (то же самое через accumulate с init 0 дало бы int 6)


Это и есть причина, по которой fold_left лучше: он не обрезает молча.

fold_left довольствуется однопроходным input-диапазоном (годится для istream_view и прочих потоков), а fold_right требует bidirectional-диапазона — ему нужно дойти до конца и пойти обратно. Поэтому «свернуть справа» поток на лету не выйдет.

• В отличие от remove, transform и copy_if из прошлого поста, свёртки НЕ принимают проекцию. «Свернуть по полю» одним аргументом не выйдет — нужна лямбда, которая сама достанет нужное:

std::vector<Task> tasks = { {"Код", 1}, {"Деплой", 2} };
int total = std::ranges::fold_left(tasks, 0,
[](int acc, const Task& t){ return acc + t.priority; });
// 3



📍Навигация: ВакансииЗадачиСобесыКанал в Max

Библиотека C/C++ разработчика

#константная_правильностьx
Please open Telegram to view this post
VIEW IN TELEGRAM
👍43👾1
📉 Инфляция грейдов, смерть джунов, новая модель найма: что происходит с IT-рынком в 2026 году

Представь лифт, который застрял между этажами, а его двери завалили арматурой. Это и есть IT-рынок в 2026 году. Грейды ничего не значат, джунов не берут, кандидаты врут в резюме, компании завышают требования, а воронку найма пересобирают с нуля. Разбираемся, что пошло не так и как это чинят.

👉 Читать дальше

📍Навигация: ВакансииЗадачиСобесыКанал в Max

Библиотека C/C++ разработчика

#свежак
😁4👍1
⛄️ Почему find_package(Foo) ищет в двух режимах?

Многие думают, что find_package — это «одна команда, один поиск». На деле под капотом работает диспетчер двух разных механизмов, и путаница между ними — частая причина «package not found» при идеально установленной библиотеке.

🔍 Когда вы пишете find_package(Foo), CMake по умолчанию сначала запускает Module mode: ищет файл FindFoo.cmake сперва в CMAKE_MODULE_PATH, а затем во встроенных модулях самого CMake. Это скрипт-разведчик, который через find_path/find_library сам ищет заголовки и библиотеки на диске.

⚡️ Если модуль не найден, включается Config mode: CMake ищет FooConfig.cmake или foo-config.cmake — файл, который поставляет сам пакет и который точно знает, где что лежит.

❗️ Важно: это последовательный поиск с откатом, а не параллельный. И порядок можно перевернуть — с CMake 3.15 переменная CMAKE_FIND_PACKAGE_PREFER_CONFIG=ON заставляет сначала пробовать Config.

find_package(Foo)              # сначала Module, потом Config
find_package(Foo CONFIG) # только Config mode
find_package(Foo MODULE) # только Module mode


❗️ Ключевое различие: FindFoo.cmake пишет кто угодно, кроме автора пакета — потребитель, сторонний разработчик или сами разработчики CMake (так поставляются FindThreads, FindOpenSSL и т.д.), и он угадывает расположение. А FooConfig.cmake поставляет сам автор библиотеки, и он обычно отдаёт готовые импортированные таргеты (Foo::Foo) с уже прописанными путями, флагами и зависимостями. Поэтому Config mode почти всегда надёжнее.

💡 На практике: если современная библиотека (через install(EXPORT)) не находится — проверьте не CMAKE_MODULE_PATH, а CMAKE_PREFIX_PATH, потому что искать нужно именно Config-файл.


📍Навигация: ВакансииЗадачиСобесыКанал в Max

Библиотека C/C++ разработчика

#под_капотом
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍2
✈️ C++26 наводит порядок в строковых литералах

До C++26 строки, которые живут только на этапе компиляции, формально не отличались от обычных литералов — и компиляторы обрабатывали их кто во что горазд.

• P2361R6 выделяет невычисляемые строки — те, что нужны только компилятору (static_assert, [[deprecated]], [[nodiscard]], _Pragma, #line, asm, имена литеральных операторов) и в исполняемый файл не попадают

• Префикс кодировки (L, u8, u, U) на них теперь запрещён: static_assert(false, L"плохо") перестаёт компилироваться

• Строка не переводится в целевую кодировку — компилятор хранит исходные символы как есть, для сообщений об ошибках

• Из управляющих последовательностей остаются только имена символов Юникода и простые вроде \n и \t. Числовые (\x1B, \077) запрещены: в неизвестной кодировке толковать их нечем

• Второй документ, P1854R4, наводит порядок в обычных литералах: непредставимые символы теперь ошибка, а не поведение на усмотрение реализации. И это исправление действует задним числом — вплоть до C++98

Формально это breaking changes. Но проверка более 90 миллионов строк открытого кода почти не нашла затронутых мест: единственные префиксы на таких строках обнаружились в тестах самого Clang. Цена миграции близка к нулю, выигрыш — предсказуемое поведение вместо зоопарка реализаций.

↗️ Пост

✏️ Натыкались ли вы хоть раз на L"..." в static_assert, или это чистка стандарта ради самой чистоты? 👇

📍Навигация: ВакансииЗадачиСобесыКанал в Max

Библиотека C/C++ разработчика

#буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🙏6😁2👍1
🐸 Подборка вакансий для C++-разработчиков за неделю

Инженер-программист (C++/Python) — от 250 000 ₽ Гибрид (Москва)

C++ Game Developer / Legacy Game Project — от 1000 и до 2000 $ Удалёнка

Разработчик C++ (Middle) — Офис (Москва)|

Разработчик С++ — Удалёнка


📍Навигация: ВакансииЗадачиСобесыКанал в Max

Библиотека C/C++ разработчика

#вакансии
🔥 Строишь ИИ-агентов? Руководитель AI/ML-направления Сloud․ru покажет, где большинство архитектур ломаются, и как этого избежать.

18 июня в 19:00 совместно с Сloud․ru проведём открытый урок «Мультиагентные системы: почему большинство архитектур переусложнены».

Спикер — Дмитрий Юдин, эксперт по масштабированию и оптимизации вычислительных ресурсов для ML. Под его руководством развивается Evolution AI Factory — цифровая среда для работы с GenAI. Он занимается развитием сервисов генеративного ИИ, инфраструктуры для обучения больших языковых моделей и внедрением интеллектуальных агентов.

Что получишь на уроке:

— критерии выбора между одним агентом и мультиагентной системой;
— разбор популярных архитектурных ошибок;
— реальные ограничения современных ИИ-агентов;
— практические рекомендации по проектированию агентных систем.

🎁 Для участников урока подготовили промокод на скидку 10 000 ₽.

🗓️ Когда: 18 июня, 19:00 (МСК)

👉 Занять место на открытом уроке
😁3
💰 Вас уже развели: 6 способов манипуляции зарплатами в 2026 году

Широкие вилки, которые никто не получает, бонусы-призраки и грейды из параллельной вселенной — рассказываем, как компании в 2026 году экономят на вас, пока вы думаете, что это нормально. Спойлер: если вы хоть раз слышали «пересмотрим через полгода», то вас уже развели.

👉 Читать дальше

📍Навигация: ВакансииЗадачиСобесыКанал в Max

Библиотека C/C++ разработчика

#свежак
👍4
🐛 Задача на выходные: есть ли проблема с deducing this?

C++23 «explicit object parameter» — мощь. Решили сделать zero-overhead геттер с идеальным пробросом самого объекта. На лайвах работает, в проде иногда мусор в строке.

struct Widget {
std::string name;
// отдаём name с тем же value-category, что и сам объект
auto&& title(this auto&& self) {
return std::forward<decltype(self)>(self).name;
}
};

const std::string& bad = Widget{"btn"}.title(); //
std::println("{}", bad);


Задача: объясни, какой ровно тип выводится у title() при вызове на rvalue Widget, почему bad ссылается на уничтоженный объект, и где здесь lifetime extension НЕ срабатывает (и почему именно для deducing-this это особенно коварно). Как спроектировать API, чтобы компилятор ловил это?

💬 Разбор — в комменты

📍Навигация: ВакансииЗадачиСобесыКанал в Max

Библиотека C/C++ разработчика

#междусобойчик
👍1
💻 3 курса по цене одного — собери стек для оффера в топовую IT-компанию

Для следующего карьерного шага мало писать код. Работодатели ждут не только знания языка, но и понимания архитектуры, алгоритмов, автоматизации, AI-инструментов и агентных систем.

Одно направление закрывает только часть задачи.

Поэтому сейчас мы предлагаем освоить сразу несколько востребованных навыков — выбери любой курс и получи доступ еще к двум бесплатно 🔥

Собери стек навыков под свою цель:

🔹 подготовка к сильным компаниям (алгоритмы, архитектура);
🔹 переход в AI-направление (ИИ-агенты, AgentOps);
🔹 развитие в ML и Data Science (математика, основы ML);
🔹 новый оффер и рост дохода.

Полученные знания применяешь в работе уже во время обучения.

Акция действует 48 часов — 13 и 14 июня.

👉 Переходи на сайт, выбирай курсы и оставляй заявку — за 10 минут поможем собрать комплект под твою цель.
📰 Свеженькое из мира C++

Подготовили подборку самых интересных материалов за неделю о разных аспектах программирования и интересных проектах в мире C++.

😎 Интересное:

Инфляция грейдов, смерть джунов — смотрим что происходит с IT-рынком в 2026 году
Почему find_package(Foo) ищет в двух режимах? — разбираемся где на самом деле CMake ищет пакеты

C++26 наводит порядок в строковых литералах — новый стандарт приносит нам улучшение строк 😊
Вас уже развели: 6 способов манипуляции зарплатами в 2026 году — хитрости, которые позволяют экономить на сотрудниках

📙 Ranges:

Алгоритмы диапазонов: Свёртки (fold)

🔹📍Навигация: ВакансииЗадачиСобесы

Библиотека C/C++ разработчика

#свежак
🎥 До открытого урока — несколько дней. Подготовили небольшую подборку материалов от нашего спикера Дмитрия Юдина.

Дмитрий руководит AI/ML-направлением в Сloud․ru и развивает Evolution AI Factory — среду для работы с GenAI: от инфраструктуры обучения LLM до внедрения интеллектуальных агентов.

С чего начать:

📺 AI-инструменты для разработчиков — как код, автотесты и ассистенты меняют рутину инженера.
📺 AI-эволюция бизнеса в эпоху генеративных моделей — агентные системы в реальных продуктах.
📺 Разработка мертва? — дискуссия о будущем профессии и роли AI в ней.
📖 Применение LLM в бизнесе — статья Дмитрия о практике внедрения и роли облака.

Одна из ключевых тем Дмитрия — практическое применение агентных систем и их ограничения.

Именно об этом бесплатный урок 18 июня в 19:00: «Мультиагентные системы: почему большинство архитектур переусложнены» 🔥

🎁 Для участников подготовили промокод на скидку 10 000 ₽ на курс «Разработка ИИ-агентов».

👉 Успей занять место на открытом уроке
😁2
🤖 Свой malloc для ОС: от наивного списка до бинов

Серия статей про аллокатор на C++ для собственной ОС — там, где нет ни стандартной библиотеки, ни готового ABI, а PageAllocator только предстоит написать.

🍿 Статьи

1. Неявный список свободных блоков с граничными тегами
2. Слияние блоков за константное время. Юнит тест для аллокатора
3. Финальный аллокатор со списками свободных блоков
4. mem_malloc_aligned

📍Навигация: ВакансииЗадачиСобесыКанал в Max

Библиотека C/C++ разработчика

#свежак
👍4😁3
🍬 EXPECT_DEATH не ловит исключение. Он запускает ваш код в отдельном процессе и ждёт его смерти

Если думал, что death-тест в GoogleTest — это просто проверка «упадёт или нет», то это не так. На деле фреймворк изолирует ваш код в дочернем процессе, дожидается его завершения и проверяет, что тот умер именно так, как вы ожидали. Сам тест-раннер при этом остаётся жив — в этом весь смысл.

💡Когда вы пишете EXPECT_DEATH(stmt, "regex"), фреймворк форкает текущий процесс. Дочерний выполняет stmt, родитель через waitpid() ждёт его завершения и анализирует статус выхода.

Зачем вообще отдельный процесс? Потому что abort(), std::terminate или сработавший assert убивают процесс по-настоящему. Поймать это в том же процессе как исключение нельзя — управление уже не вернётся. Единственный способ протестировать смерть, не убив сам тест-раннер, — изолировать её в ребёнке.

EXPECT_DEATH(
{ std::abort(); },
".*"
);


❗️ Родитель и ребёнок после форка — два независимых адресных пространства (copy-on-write). Краш в ребёнке для родителя — просто ненулевой код возврата или сигнал.

❗️Death-тест — это не try/catch, это управляемое самоубийство подпроцесса. Если держать это в голове, перестаёшь удивляться, почему std::cout внутри блока ведёт себя странно.


А вы проверяете abort()-ветки или оставляете их «на авось»?

📍Навигация:
ВакансииЗадачиСобесы

Библиотека C/C++ разработчика

#константная_правильность
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42🙏2
🤕😱 Канала не хватает одного — твоего буста. Не лайка, не репоста. Именно буста, который реально качнёт канал вверх

Если думал, что от одного голоса ничего не зависит, то это не так. На деле каждый буст поднимает уровень канала и открывает ему новые возможности. А тебе за это больше полезностей в канале‼️

За что бустить?

За Сторис — наш формат для небольших, но полезных находок, которые жалко оставлять «за кадром»:

• интересные инструменты
• короткие технические заметки
• полезные ссылки
• вопросы для программистов
• быстрые опросы


👾 Жми кнопку буста под этим постом. Этим ты внесёшь ощутимый вклад в развитие канала.

➡️ Буст канала

Библиотека C/C++ разработчика
Please open Telegram to view this post
VIEW IN TELEGRAM
1😁1
🎱 Проекции: Что такое проекция?

Одна из полезнейших тем в C++ диапазонах — это проекции.

Проекция — это функция, которая «извлекает» ключ из элемента перед тем, как алгоритм с ним работает. Подавляющее большинство алгоритмов из std::ranges принимают необязательный параметр proj; по умолчанию там std::identity — элемент идёт как есть.


ranges::sort — сортировка по полю

Возьмём те самые задачи из прошлого поста:

struct Task { std::string name; int priority; };
std::vector<Task> tasks = { {"Код", 1}, {"Деплой", 3}, {"Тесты", 2} };

std::ranges::sort(tasks, {}, &Task::priority);
// порядок: Код(1), Тесты(2), Деплой(3)


Здесь {} — компаратор по умолчанию (ranges::less), а &Task::priority — проекция. Для каждой пары алгоритм считает less(a.priority, b.priority). Помните, в свёртках, чтобы сложить по priority, пришлось писать лямбду? Тут поле достаёт сама проекция.


🎨 Проекция по указателю на член

Самый частый случай — &Тип::поле. И работает не только в sort:

// найти задачу с priority == 3
auto it = std::ranges::find(tasks, 3, &Task::priority);
// *it == Task{"Деплой", 3}

// посчитать задачи с priority > 1
auto n = std::ranges::count_if(tasks,
[](int p){ return p > 1; }, &Task::priority);
// n == 2


Обратите внимание на порядок: у find проекция идёт сразу после искомого значения (компаратора у него нет), а у count_if — после предиката. У каждого алгоритма свой набор параметров, проекция в нём всегда последняя.


🧁 Проекцией может быть что угодно вызываемое

Не только поле. Подойдёт указатель на метод, лямбда, свободная функция — всё, что переваривает std::invoke:

std::vector<std::string> v = {"apple", "fig", "banana"};
std::ranges::sort(v, {}, &std::string::size); // по длине
// "fig"(3), "apple"(5), "banana"(6)

std::vector<int> nums = {-5, 2, -1, 3};
std::ranges::sort(nums, {}, [](int x){ return std::abs(x); }); // по модулю
// -1, 2, 3, -5



🎁 Проекция меняет ВЗГЛЯД, но не результат

Это главное, что надо уложить в голове. Проекция влияет только на то, ПО ЧЕМУ алгоритм принимает решения. Возвращает он по-прежнему исходные элементы, а не спроецированные значения:

auto top = std::ranges::max(tasks, {}, &Task::priority);
// top — это Task{"Деплой", 3}, а НЕ число 3
// (и это копия: max возвращает элемент по значению)

auto it = std::ranges::min_element(tasks, {}, &Task::priority);
// *it — Task{"Код", 1}, итератор на сам элемент (копии нет)


То есть проекция — это «по какому ключу», а не «во что превратить». Если нужно именно превратить элементы — это уже views::transform.


🍕 У бинарных алгоритмов проекций две

Там, где сравниваются два диапазона (equal, mismatch, …), проекций тоже две — по одной на каждый вход:

std::vector<Task> a = { {"X", 1}, {"Y", 2} };
std::vector<Task> b = { {"A", 1}, {"B", 2} };

// равны ли списки по приоритетам, игнорируя имена?
bool same = std::ranges::equal(a, b, {}, &Task::priority, &Task::priority);
// {} — предикат по умолчанию, дальше proj1 и proj2
// true: 1 == 1, 2 == 2



‼️ Несколько подводных камней

Порядок аргументов. proj идёт после компаратора, а не вместо. sort(tasks, &Task::priority) — указатель на поле не годится в компараторы → простыня ошибок. Правильно: sort(tasks, {}, &Task::priority).
Проекцию зовут много раз. В sort — на каждом сравнении, O(n log n) вызовов. Тяжёлую (парсит строку) выгоднее посчитать заранее и сортировать по готовым ключам.
Проекция ≠ преобразование вывода. На выходе всегда исходные элементы. Превратить их — это views::transform.
Свёртки без проекций. У fold_* параметра proj нет (хотя у for_each и transform есть). «Свернуть по полю» — только лямбдой или через views::transform.


📍Навигация: ВакансииЗадачиСобесы

Библиотека C/C++ разработчика

#константная_правильностьx
Please open Telegram to view this post
VIEW IN TELEGRAM
9