C++ and other lectures
8.45K subscribers
39 photos
2 files
209 links
Учебный канал в Телеграм: тут будут анонсы и ссылки на лекции и стримы. Написать автору: @Tilir
Download Telegram
Готовлюсь к лекции по ranges. Есть такой вопрос (а скорее даже опрос) для уважаемых подписчиков этого канала.

Вот есть пример в котором GCC и clang не согласны.

https://godbolt.org/z/1ro9x3nh1

Кто-то, ясное дело, прав, кто-то нет. Мне интересно как бы вы аргументировали кто прав в C++20 и почему.

Также задал вопрос на stackoverflow: https://stackoverflow.com/questions/74668972/c20-move-only-ranges-gcc-vs-clang-on-istream-view-copy

Большая просьба именно проиллюстрировать ход мысли. Куда пойдёте в стандарте, что будете смотреть.

#questions
👀9🤔7
Ещё один вопрос по диапазонам. Надеюсь после моей лекции все устыдились и ответы будут обстоятельными и интересными.

Есть код:

struct S { int x, y; };
std::vector<S> v{{1, 0}, {2, 0}, {4, 0}};
auto it = ranges::find(v | views::transform(std::mem_fn(&S::x)), 4).base();

Что тут происходит: я проецирую вектор на инты, ищу там 4 и прошу итератор (base) на исходный вектор.

https://godbolt.org/z/hhWaPsjsj

Он не работает, но GCC и ToT Clang говорят разные вещи.

У clang там просто ranges::dangling (хотя как может провиснуть итератор на существующий вектор?)
У gcc там нечто более интересное.

Опять таки исходный библиотечный код один и тот же. Как бы вы это исследовали? Кто тут прав?

#questions
🤔14👍1👀1
Всем привет. Потёр немного оффтопика про fixed-width типы (int8_t, int16_t и т.д.) из другой ветки, но я вижу у людей накипело и предлагаю для on-topic обсуждения эту ветку.

Пока что моё нынешнее личное отношение такое: fixed-width типы это зло и любое их применение это ошибка. Но у меня действительно тут объективно слабовато с аргументацией.

По пунктам из того что есть:

(1)

Если у вас есть 32-битная архитектура (например 32-битный ARM или RISCV) и вы использовали в программе int64_t, как компилятору и библиотеке это трактовать? Вы ждёте ошибку компиляции или вы ждёте int_least64_t и обработку по кускам с хранением в двух регистрах и т.д.? Если да то почему собственно и кто вам это обещал?

(2)

Что вы вообще хотите сказать используя такие типы? Что ваша программа не будет работать если тут не 64 бита? Что вы хотели бы чтобы тут было 64 бита? Что вам всё равно сколько тут бит но вы считаете себя умнее компилятора и вот соптимизировали для x86?

В первом случае это static assert.

(3)

Люди недооценивают опасность (даже в случае если точные 64 бита есть) при переносе с платформы на платформу типов которые меняют статус в зависимости от дефайна. Рассмотрим две платформы на одной из которых int64_t определён в int, а на другой в long long. Допустим вы заводите битфилд такого типа. Вы понимаете последствия?

С удовольствием послушаю что вы думаете на эту тему и может быть скорректирую своё мнение. Только пожалуйста вежливо.

#questions
👍27🔥9🤔6🤷‍♂4🤡2🥴2🗿1🤷1
Работа над ошибками (нужна помощь зала).

В комментариях мой уважаемый подписчик Роман Митин указал что я на лекции показал неправильный пример bounded MPMC queue -- на самом деле извлечение и вставка там шли с одного конца и таким образом это был скорее bounded MPMC stack. Для многопоточной среды разница не так велика -- задачи ставятся в "очередь" и разбираются консьюмерами и в общем по циклограмме работы сложно отличить что там было. Но я решил сделать настоящую очередь и заодно улучшить тесты.

И вот тут я обратил внимание что у меня было ещё несколько ошибок, пока в комментариях не замеченных.

(1) В случае multi-producer делать wake_and_done надо на всех продьюсеров один раз иначе бывает так что консьюмеры повыходили но не все продьюсеры ещё закончили.
(2) Саму функцию wait_and_pop надо делать с сигнатурой bool wait_and_pop(T &Data) чтобы понимать есть там что консьюмить или нет
(3) Внутри wait_and_pop условие должно выглядеть так:

CondCons.wait(Lk, [this] { return !empty() || done(); });
if (empty())
return false;

Даже если у нас сигнализирован done, задачи могут быть недоразобраны и поэтому критерий return false это только empty.

(4) Внутри push признак done вообще проверять не надо т.к. это признак отработки всех продьюсеров. Там играет роль только full.
(5) В интерфейсе необходим метод is_empty_and_done() чтобы по нему консьюмеры понимали когда начинать выходить.

В общем это жесть. Пять ошибок в довольно простом коде и я не уверен что я ещё чего-то не пропустил.

Полу-финальные версии bounded stack и bounded queue с тестами на то что они не теряют задач я выложил сюда:

https://github.com/tilir/cpp-masters/blob/master/queues/classic_queue.cc
https://github.com/tilir/cpp-masters/blob/master/queues/classic_stack.cc

Нужна помощь зала в проверке не упустил ли я ещё чего-нибудь. Хочу в среду с этого начать лекцию и не хотелось бы облажаться ещё в чём-нибудь столь же тонком.

#questions
👍34🤯10👏4🤨1
Это закреплённый пост, начните с его прочтения.

Прецедентные правила канала (просто почитайте и соотнесите с ними то что вы хотите написать): https://t.me/cpp_lects_rus/169

В качестве технического дополнения: пожалуйста не оставляйте в группе канала постов, не прикреплённых к веткам обсуждения.

Для сбора запросов на новые ветки используйте direct messages на канале, они бесплатны. Информация как их найти тут: https://t.me/cpp_lects_rus/287

На канале введена система тегов для навигации. Ниже теги изложены в алфавитном порядке.

#author_event -- встречи с читателями
#books -- обзоры чужих книг
#c_graduate -- изложение на C для первого курса
#conference -- что-то касающееся конференций в которых я участвую
#combinatorics -- что-то про комбинаторику
#compilers -- алгоритмы оптимизирующей компиляции
#computability -- что-то про вычислимость
#cpp_graduate -- изложение на C++ для второго курса
#cpp_postgraduate -- изложение на C++ для магистратуры
#interview -- интервью со мной в разных местах
#graphics -- что-то про GPU или GPGPU
#happynewyear -- традиционное подведение итогов года
#knuth -- вольные переводы Дональда Кнута
#llm -- общение с микроволновками
#official -- под этим тегом я говорю от своего лица, обычно какие-то технические вещи и объявления
#publications -- публикации в научных журналах и не только
#riscv — нечто про открытую и расширяемую архитектуру RISC-V
#talks -- обзоры чужих докладов
#toolchain -- что-то про системы компиляции, а также ассемблеры линкеры и всё такое
#torrent -- публичная выкладка пакетами
#questions -- предложения что-то обсудить

Размечены все существующие посты. Если найдёте ошибки в разметке сообщайте.

Ютуб-канал с моими лекциями: https://www.youtube.com/@tilir
Рутуб-канал с ними же: https://rutube.ru/u/cpplectsrus/

Курс по языку C: https://youtube.com/playlist?list=PL3BR09unfgchRxdDws74aY4mlSk9eYGEs
Базовый курс по C++: https://www.youtube.com/playlist?list=PL3BR09unfgciJ1_K_E914nohpiOiHnpsK
Магистерский курс по C++: https://www.youtube.com/playlist?list=PL3BR09unfgcgf7R88ZQRQqWOdLy4pRW2h
Оптимизирующие компиляторы: https://www.youtube.com/playlist?list=PL3BR09unfgcjBG1H9xRUesaQX6nCsobs1

#official
🔥107👍346❤‍🔥6
Всем привет. И снова настало время обратиться за небольшой помощью к залу.

В своей лекции про многопоточность я использую иллюстрацию замечательного русского художника В. Г. Сутеева (три котёнка это три потока, труба это критическая секция).

И вот я подумал почему бы не попросить картинку у нейросети. Я использовал Кандинского 2.1 и пытался формулировать запросы.

Запросы были такие: "три котёнка в трубе", "три котёнка ползут по трубе", "три котёнка внутри трубы". Я сгенерировал наверное изображений тридцать, прикладываю три самых симпатичных. Но это всё не то.

Мне нужна картинка как три котёнка ползут внутри лежащей на земле трубы по одному.

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

UPD: результаты конкурса https://t.me/cpp_lects_rus/173

#llm #questions
😁42👍12🔥9💔1
Интересный пример предварительной пессимизации (или несовершенства компиляторов, как посмотреть), инспирированный решением одного моего студента.

https://godbolt.org/z/qa59c5MM1

Тут очевидно, что функция double_area делает то же самое, что wicked_double_area (если раскрыть скобки). Мало того, весь контекст локальный и всё доступно для оптимизаций. Но и clang и gcc не справляются — в генерированном коде получается шесть умножений против двух.

Кто возьмётся исследовать что происходит?

#questions
#compilers
🤔11👍2🥴2
В продолжение предыдущего поста выношу из комментариев обстоятельный диалог с нейросетью на тему упрощения алгебраических выражений.

Я хотел добиться, чтобы мне упростили a * c - a * d - b * c - e * f + e * d + b * f до (a - b) * (c - d) - (e - b) * (f - d). Там сначала разминочный вопрос который сетка с лёгкостью прошла, а вот дальше...

https://chat.openai.com/share/8894392f-253b-4ade-a059-d2dad90619da

У меня не получилось.

Хочется обратиться к экспертам в инжиниринге запросов на моём канале. А вы сможете добиться от нейросети правильного ответа?

#llm
#questions
👍12🗿5
В семинаре 2.3 кто-то мог в конце пропустить небольшой шедевр от одного из студентов.

Вот чуточку причёсанная мной но близкая к оригиналу студенческая трактовка Problem FT. Определяет простоту числа через тест Ферма.

https://godbolt.org/z/PsvMs3fG1

Обратите внимание: программа совершенно корректно справляется с 49979687 (простое) и с 271747319 (составное 15791×17209).

Разумеется проблема тут в том что вместо настоящего случайного числа rand() использован просто адрес функции rand и он себя показывает неплохим случайным числом (!)

Но давайте заметим ещё кое-что, чего я на семинаре не упомянул. Именно в этом коде замена rand на rand() способна ухудшить ситуацию. Кто увидит почему? Кто также назовёт ещё одну потенциальную проблему в этом коде из-за которой (даже при rand() как вызове) на самом деле легко подобрать тест который не будет пройден?

#questions #c_graduate
🤯24👍6😁6🔥3🥱1
Немного странного C++.

Уважаемый читатель моего канала @MSerhiy обнаружил забавную вещь: для структур и для примитивных типов вот в этом примере действуют разные правила перегрузки: https://godbolt.org/z/YT9bo7ore

Я довольно быстро раскопал ответ в стандарте.

C++20, [expr.type] "If a prvalue initially has the type “cv T”, where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis"

Но я что-то задумался в процессе. Вот чисто гипотетически: а зачем так было сделано? Чему и когда это поможет? У меня нет идей.

Предлагаю в этой ветке поспекулировать насчёт источника этого правила.

#questions
🤔18🔥10🤡1
День прошёл не зря — я узнал третье отличие class от struct.

Игра следующая: в контексте где возможны и class и struct найти где они будут вести себя по разному.

Общеизвестны 2 отличия:
(1) В class все поля по умолчанию private, в struct — public.
(2) Наследование в структуре по умолчанию публичное а в классе приватное.

Первое обычно знают все. Второе иногда вспоминают на интервью. Но сегодня я узнал третье.

(3) В качестве шаблонного параметра class означает тип, а struct начиная с C++20 означает NTTP с типом этой структуры (или класса с тем же именем, что, ИМХО, особенно прекрасно).

Наслаждаемся: https://godbolt.org/z/vsWzsTK8r

Найдётся ли четвёртое? Жду ваших предложений =)

#questions
🤯66🔥25👍186🤷5
Подводим итоги конкурса нейросетей.

30 апреля 2023 года я объявил конкурс нейросетей на лучшую картинку по запросу.

https://t.me/cpp_lects_rus/99

Убедительную победу в конкурсе нейросетей одержала человек Даша https://t.me/dariaemacs чью картинку я в итоге и использовал в новой пачке слайдов к лекциям. Впрочем, в том посте были и довольно милые варианты.

У Даши тоже есть блог по программированию и подписчиков там почти как у меня https://youtube.com/@DariaEmacs

А рисование - это её хобби, работы можно посмотреть тут https://www.livemaster.ru/dariaemacs/category/205?v=0&sortitems=0&cid=0 (мне показались отличными).

#llm #questions
😁38🔥35👍1513🍌1
В тему последнего семинара по C, но расширяя её на C++, мой уважаемый подписчик @A_A_Arg задаёт вопросы, в равной степени интересные и для меня тоже так что хочется их вынести на общее обсуждение.

(1) Каковы шансы, что std::linalg  попадет в состав стандартной библиотеки C++26, и хорошо ли это?

(2) Что сейчас считается лучшим пакетом на C++ для линейной алгебры (например, в отношении скорости и встроенных возможностей распараллеливания)?

Если на канале есть специалисты, поделитесь пожалуйста со всеми.

#questions
🤔228🔥5👍1🥱1
Пятница, вечер, самое время для свежепридуманного этюда по C++. Придумал утром, сегодня опробовал на коллегах и остался доволен.

https://godbolt.org/z/8EaEbPz9x — это не работает
https://godbolt.org/z/6b3977Pac — то же, но без инстанцирования структуры отлично работает

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

Увы, призов, кроме зрительских симпатий, не обещаю.

#questions #cpp_postgraduate
👍36🤯1910
Загадка недостающих страниц (конкурс с призом)

Участники процесса: редактор Алиса и наборщик Боб (имена не настоящие, взяты сами понимаете откуда).

На этапе предзаказа Алиса посылает Бобу некий драфт, который Боб адаптирует для листалки на сайте и сохраняет у себя.

Далее перед печатью в типографии Алиса посылает Бобу финальный печатный файл.

Но в ночь перед печатью, Алиса замечает на четырёх страницах, а именно на страницах 22, 167, 169 и 173 некую проблему, которая не очевидна на этих страницах, но после печати в типографии станет очевидной и неприятной. Поэтому она пишет Бобу просьбу заменить эти четыре страницы на те, которые она прислала.

Боб заменяет, но случайно делает это не в финальном файле, а в драфте и отправляет на печать драфт с заменёнными четырьмя страницами.

Чему нас учит эта история? Не надо коммитить без CI в ночь перед релизом.

В общем в истории с моей книгой все события -- как будто бы из нашей жизни.

А теперь конкурс. Он требует много телепатии. Я прикладываю четыре страницы, выбранные под замену. Тот, кто первым догадается что именно на них общего и что смутило Алису, бесплатно получит мою книгу из числа авторских экземпляров (когда их напечатают и выдадут мне) с моим автографом.

#questions
👍62😁32🔥85💯5🌭3👎1
Всем привет. Очередная лекция по компиляторам завтра в 9 утра, а сегодня вечер пятницы и небольшой брейн-тизер по C++.

template<typename T = void>
int foo(int x) { return 1; }

int foo(...) { return 2; }

template<typename T = void>
int bar() { return 1; }

int bar(...) { return 2; }

int main() {
std::cout << foo(2) << std::endl; // ?
std::cout << bar() << std::endl; // ???
}


https://godbolt.org/z/qfsEvxh4E

Громадное спасибо за него Владиславу Белову https://t.me/you_are_RTshnik наткнувшемуся на эту красоту во время выполнения одного из моих заданий.

Задача довольно обычная — объяснить в чём разница с детальными ссылками на C++23. Призов не будет, кроме зрительских симпатий.

P. S. книгу обещают перепечатать к 15 ноября.

UPD: Уважаемый подписчик Артём Колпаков @ddvamp развил и усилил пример до https://godbolt.org/z/ab31ah199

#questions #cpp_postgraduate
🔥50🤪10👍8🤔2🥴1🌚1🫡1💘1
И снова время пятничного зачила. Наливайте пивка, открывайте последний драфт стандарта C++23 (N4950) и поехали.

Рассмотрим вот такой пример, обозначим его [1].

class X {
template <typename U> struct Hidden {};
};

template <typename T>
using Wrapper = typename X::template Hidden<T>;

int main() {
Wrapper<float> w;
}


https://godbolt.org/z/sMnec5nx4

В нём clang и gcc почему-то не выдают ошибок, хотя имя является скрытым. Тут хочется воскликнуть — ну наверное по стандарту открытость using зависит от него а не от того что он алиасит. Не торопитесь, читайте дальше.

Уберём шаблоны и получим пример [2].

class X {
struct Hidden {};
};

using Wrapper = typename X::Hidden;

int main() {
Wrapper w;
}


https://godbolt.org/z/q9TYMeaYo

Вроде он мало чем отличается, тоже using, но тут оба компилятора отказываются компилировать.

Теперь пойдём от [1] в другом направлении: заменим using на struct и получим пример [3].

class X {
template <typename U> struct Hidden {};
};

template <typename T>
struct Wrapper : X::template Hidden<T> {};

int main() {
Wrapper<int> w;
}


https://godbolt.org/z/Gs1s3z8qn

Оба компилятора отказываются компилировать. То есть using всё-таки важен? Ситуация становится интересней.

И теперь сделаем последний шаг: запишем пример [3], но не будем инстанцировать шаблон (т.е. уберём функцию main) и получим пример [4].

https://godbolt.org/z/9EM1avbxe

И внезапно тут мнения компиляторов расходятся. Clang выдаёт ошибку, тогда как gcc отлично компилирует.

Вопросы:
1. Обоснуйте с точки зрения стандарта чем отличается [1] от [2]
2. Обоснуйте с точки зрения стандарта чем отличается [1] от [3]
3. Обоснуйте с точки зрения стандарта какой из компиляторов прав в [4]?

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

Призов не обещаю (кроме зрительских симпатий). Рекомендуется сначала подумать самостоятельно, потом заезжать в комментарии.

#questions
🤔42😁17👍12🫡6🤯5🔥4😱21
Пятница, вечер, время почитать стандарт. Увертюра в четырёх актах.

1. Рассмотрим следующий пример. Тут компилятор считает запятую разделителем для макроса, а не для шаблона.

https://godbolt.org/z/s7s453v1o

Что делать? Очевидно поставить скобки:

2. https://godbolt.org/z/86Wj5nh4Y

Стало лучше, но всё ещё можно сломать. Как сломать? С помощью фигурных скобок и фантазии:

3. https://godbolt.org/z/v3qnf519v

Как починить?

После некоторой игры с компилятором я нашёл решение работающее на обоих основных компиляторах (я верю вы его тоже легко найдёте).

4. https://godbolt.org/z/1919eKvnr

Предлагается обосновать по стандарту почему это работает.

#questions
🔥39👍9💩1
Пятница, вечер. Время чилаута и развлекательного C++.

Представим у вас есть куча специализаций некоего шаблона функции foo.

template <typename T> int foo() { return 1; } 
template <> int foo<int>() { return 2; }
template <> int foo<float>() { return 4; }


И функция sumfoos которая подставляет по ним пачку типов и как-то её сворачивает. Ну скажем складывает.

template <typename ...T>
int sumfoos() { return (foo<T>() + ...); }


Вы хотели бы написать шаблон функции apply_sumfoos с вот такой сигнатурой

template <typename Tuple> auto apply_sumfoos();


Идея в том что он принимает кортеж, разворачивает его и для его содержимого вызывает sumfoos.

std::tuple<int, float, double> t;
assert(apply_sumfoos<decltype(t)>() == 7);


Можно предложить кривой и косой, уродливый как черт с рогами, но рабочий вариант с dummy-аргументом.

https://godbolt.org/z/zxY1qf9hT

Но это не наш метод. Я утверждаю что есть более красивые способы (и даже можно обойтись без сворачивания с index sequence).

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

UPD: мой вариант вычислили за 20 минут. Горжусь своим каналом ))

UPD2: выношу из комментариев самые интересные варианты.

0. Просто уход от nullptr за счёт type_identity, но всё ещё dummy arg https://godbolt.org/z/P41eeTcfK via @PaRat07
1. Биндинг свёртки: https://godbolt.org/z/85EhzdWve совместно @savvatelegram и @xray_3d
2. Рефлексия: https://godbolt.org/z/Pdqd75nxq via @xray_3d
3. Вывод типов и deduction guides: https://godbolt.org/z/6zTT6M8zh via @redPergament
3a. Его разновидность через оператор приведения: https://godbolt.org/z/cTh1W3r3e от него же
4. Hana-style (я добавил к решению подписчика пару consteval потому что смог): https://godbolt.org/z/GxcqKnWMK via @n13625124998637487500
4a. Его очень красивая и лакончиная разновидность через decltype (я тоже добавил consteval от себя) https://godbolt.org/z/zjErr58zz via @alamat1
5. Виртуозный std::apply https://godbolt.org/z/Ydd5e86oP via @savvatelegram
5a. То же самое руками через index sequence https://godbolt.org/z/6feh3fvex via @vmishanin
6. Сохранение промежуточного адреса инстанцированной функции https://godbolt.org/z/racKGYnW1 опять @xray_3d
7. in_place_type подход https://godbolt.org/z/Gq9G9n773 via @alamat1

Ну и самый наивный вариант: https://godbolt.org/z/48jnhKz45 здесь в редакции @ePilnikoff но вообще до него многие дошли и он совпадает с моим решением.

Наивный вариант очень интересно улучшил @s_i_g_a до состояния https://godbolt.org/z/GePnj8qE1 чтобы функция принимала любой tuple-like тип вроде того же std::array. Понятно что так можно улучшить каждый из предложенных вариантов.

Итого мы с вами нашли десять нетривиальных и принципиально разных способов добиться цели. Очень круто.

#questions
🔥7185👍3🤔2🆒1💊1
Вечер пятницы и время чилаута в области C++. На этот раз мы снова сыграем в увлекательную игру "кто из компиляторов прав".

Я вытащил этот пример из переписки со студентом более чем годичной давности и проверил на свежих gcc и clang. Они всё ещё не согласны друг с другом.

https://godbolt.org/z/fe14q8aoz

Это упражнение на чтение стандарта, так что ссылки на стандарт обязательны.

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

#questions
👍246🔥2🐳2