C++ Moscow
447 subscribers
6 photos
66 links
Информационный канал московского сообщества программистов на C++

Чат: @cppmoscow_chat
Бот обратной связи: @cppmoscow_bot
Организатор: @eoanermine
Download Telegram
#quiz #explanation

Обычно static_assert(false) вызывает ошибку компиляции, но в данном случае он используется в шаблоне, который нигде в программе не инстанцируется. Так что логично было бы ожидать, что в этом коде все хорошо и он выведет единицу. Однако, согласно C++20 и более ранним стадартам, поведение будет иным:

[temp.res.general#8]
The program is ill-formed, no diagnostic required, if:
— ...
— a hypothetical instantiation of a templated entity immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter...

static_assert(false) не зависит от шаблонных параметров и, если бы мы инстанцировали класс A немедленно после его объявления, он бы всегда вызывал ошибку компиляции (то есть, был ill-formed). Так что наша программа, согласно стандарту C++20, является IFNDR (ill-formed, no diagnostic required) — то есть, ее поведение неопределено.

Но в C++23 формулировки были изменены:

[temp.res.general#6]
The program is ill-formed, no diagnostics required, if:
— ...
— a hypothetical instantiation of a templated entity immediately following its definition would be ill-formed due to a construct (other than a static_assert-declaration that fails) that does not depend on a template parameter

Появилось исключение из правил именно для static_assert, так что в C++23 данный код корректен. На экран будет выведено 1
👍3
#quiz #code

Каким будет результат выполнения программы ниже? Делитесь своими мыслями в комментариях! Правильный ответ и его объяснение будут опубликованы в 18:00 по Москве.

#include <initializer_list>
#include <iostream>

class C {
public:
C() = default;
C(const C&) { std::cout << 1; }
};

void f(std::initializer_list<C> i) {}

int main() {
C c;
std::initializer_list<C> i{c};
f(i);
f(i);
}
🔥2
Каким будет результат работы программы выше?
Anonymous Poll
36%
1
24%
11
30%
111
9%
Compilation error
#quiz #explanation

В данном коде копирование может произойти лишь в трех местах:
1.
std::initializer_list<C> i{c}
2. Первый f(i)
3. Второй f(i)

Так в каких же из них оно происходит? [dcl.init.list] определяет то, как создается std::initializer_list следующим образом:

An object of type
std::initializer_list<E> is constructed from an initializer list as if the implementation generated and materialized a prvalue of type “array of N const E”, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list<E> object is constructed to refer to that array.

То есть, когда мы создаем
i, создается временный массив объектов типа C, инициализируемый копированием. Так что в пункте 1 копирование действительно происходит и на экран выводится 1.

Далее мы дважды вызываем функцию
f, принимающую аргумент по значению. Так что для каждого из вызовов делается копия std::initializer_list. Вызывает ли это копирование всех его элементов? Нет, так как std::initializer_list не владеет своими элементами. Как было сказано в цитате выше, он лишь ссылается на временный массив.
И это дополнительно поясняется в
[initializer_list.syn]:

Copying an initializer list does not copy the underlying elements

Ответ: 1
🔥3👏2
#proposals #resources

Каждый месяц комитет по стандартизации C++ (также известный как WG21) публикует свою „переписку“: все предложения (пропозалы) в стандарт за последний месяц, каждое из которых по результатам голосования среди членов WG21 может быть в него включено.

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

Какие пропозалы из нее вам кажутся наиболее интересными или каких полезных фич, по вашему мнению, в этом списке не хватает? Присоединяйтесь к обсуждению в комментариях!
🔥2
#quiz #code

Каким будет результат выполнения программы ниже? Делитесь своими мыслями в комментариях! Правильный ответ и его объяснение будут опубликованы в 18:00 по Москве.

#include <type_traits>
#include <iostream>

using namespace std;

struct X {
int f() const&&{
return 0;
}
};

int main() {
auto ptr = &X::f;
cout << is_same_v<decltype(ptr), int()>
<< is_same_v<decltype(ptr), int(X::*)()>;
}
🔥3
Каким будет результат работы программы выше?
Anonymous Poll
62%
00
29%
01
0%
11
14%
10
#quiz #explanation

Стандарт гласит:

[dcl.fct#8]
The return type, the parameter-type-list, the ref-qualifier, the cv-qualifier-seq, and the exception specification, but not the default arguments, are part of the function type.

То есть, ref-квалификаторы (в нашем случае
const&& для X::f) являются частью типа функции, так что тип ptr это int(X::*)() const&&.

Ответ: 00
👍2
C++ Moscow
Спасибо всем, кто посетил наш первый митап оффлайн и всем, кто ждал трансляции! К сожалению, по техническим причинам ее провести не удалось — однако, в течение недели доклады будут перезаписаны и опубликованы в хорошем качестве на нашем канале. Не всё получилось…
Работа работой и учеба учебой, но наши организаторы не дремлют и начинают строить более детальные планы на следующий митап..

А каким бы хотели видеть его вы? Поделитесь своими мыслями в комментариях!
❤‍🔥5🔥1
#quiz #code

Каким будет результат выполнения программы ниже? Делитесь своими мыслями в комментариях! Правильный ответ и его объяснение будут опубликованы в 18:00 по Москве.

#include <iostream>

using namespace std;

template <class T> void f(T) {
static int i = 0;
cout << ++i;
}

int main() {
f(1);
f(1.0);
f(1);
}
👍4
Каким будет результат работы программы выше?
Anonymous Poll
12%
123
10%
111
76%
112
5%
Compilation error
#quiz #explanation

Стандарт гласит:

[temp.fct.spec]
Each function template specialization instantiated from a template has its own copy of any static variable.

То есть, каждое инстанцирование имеет свои копии статических переменных. В нашем коде имеется два инстанцирования: для
T = int и T = double. Так что первый и третий (но не второй) вызов f разделяют между собой одну статическую переменную.

Ответ: 112
👍5
Вторая встреча московского сообщества программистов на C++ пройдет 19 ноября (Вс) с 15:20 до 18:00 по адресу Москва, Малый Конюшковский переулок, д. 2 (оффлайн + онлайн трансляция докладов)

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

Кроме того, мы будем рады всем желающим выступить с мини-докладом продолжительностью до двадцати минут на любую тему, связанную с программированием на C++ (заявки принимаются до 15 октября включительно)
Свяжитесь с нами, и мы поможем вам на всех этапах: от подбора темы для выступления (если вы ещё с ней не определились) до подготовки красивой и ясной презентации

Заходите в чат по ссылке, регистрируйтесь на мероприятие (если вы планируете посетить его очно, то регистрация обязательна), и приходите на нашу встречу, будет интересно!
🔥7
Корутины (сопрограммы) — одно из нововведений C++20, крайнего из на данных момент опубликованных стандартов. Хоть статей про них написано уже много, сами по себе они являются достаточно сложными для понимания и осознания: вместе с ними приходят сразу четыре новые сущности (promise object, coroutine handle, coroutine state, awaitable), которые программист должен постоянно держать в уме.

Множество статей и докладов рассматривают корутины на примере реализации генераторов (подобных питонячьим) — одного из самых элементарных и распространенных их приложений, что можно представить. Но что говорить, когда даже сам комитет по стандартизации C++ не смог реализовать нормальный генератор (то, что все же у него получилось, вошло в C++23 под названием std::generator)

Но не будем о грустном. Несмотря на то, что корутины тяжело писать, пользоваться ими легко и приятно! Будем радоваться, ведь всю эту неделю мы будем делиться с вами статьями и докладами, посвященными сопрограммам! Разберемся в них, во всех деталях, вместе
🔥5👍2
#cpp20 #coroutines

Начнем же наш путь! Первые статьи в нашем меню:

1. Habr: Корутины C++20 в примерах
2. Habr: Готовимся к С++20. Coroutines TS на реальном примере

Обе они вводные, но если первая рассматривает исключительно то, как корутины (кем-то за нас написанные) использовать, то вторая уже слегка приоткрывает завесу: что у них под капотом?

Если эти статьи кажутся вам слишком лайтовыми, оставайтесь на связи, впереди нас ждет хардкор!
🔥5👍2
#cpp20 #coroutines

Не будем вас томить, следующие статьи и доклады раскрывают корутины наиболее детально:

1. 🇷🇺 Habr: Корутины в C++20 — что это и как с ними работать
2. 🇷🇺 Habr: C++20. Coroutines
3. 🇬🇧 David Mazières: My tutorial and take on C++20 coroutines
4. 🇬🇧 Lewis Baker: Asymmetric Transfer

Выбирайте любую по своим языковым предпочтениям — не ошибетесь. Но как наиболее фундаментальный и всеобъемлющий труд я рекомендую серию статей Assymetric Transfer (Lewis Baker). Это лонг-лонг рид, но он абсолютно того стоит: теоретические основы корутин; механизмы их работы: operator coawait, promisetype, симметричный перенос; какие преобразования над нашим корутинным кодом выполняет компилятор — все это раскрывается во всех деталях, и вряд ли после его прочтения у вас останется хоть один вопрос о том, как работают сопрограммы.

Если же вы больше предпочитаете видео, то на тему корутин есть несколько хороших докладов:

1. 🇬🇧 Andreas Fertig: C++20’s Coroutines for Beginners — рассматривающий корутины на основе примеров;
2. 🇬🇧 Andreas Weis: Deciphering C++ Coroutines - A Diagrammatic Coroutine Cheat Sheet — больше углубляющийся в анатомию корутин и проводящий связи между их компонентами, как они между собой взаимодействуют.

И две прекрасные лекции, детальные и с прекрасной подачей:

1. 🇷🇺 Константин Владимиров: Сопрограммы, часть 1 — Обзор разновидностей сопрограмм и их основных частей, дополненный множеством интересных упражнений: собственный генератор, исследование объектов ожидания и разбор тонких и сложных проблем;
2. 🇷🇺 Константин Владимиров: Сопрограммы, часть 2 — Варианты симметрии в корутинах, их применение в конечных автоматах, многопоточности и асинхронности.

И это все, конечно, очень хорошо, но как дела обстоят с инфраструктурой для корутин: ведь обычно нам хочется использовать готовые классы generator, task и так далее, а не писать их самостоятельно, и насколько хорошо их поддерживают компиляторы? Поговорим об этом в следующий раз!
🔥9👍3
#cpp20 #coroutines

⁠Если говорить об инфраструктуре и поддержке корутин в компиляторах, то, к сожалению, C++20 не принес совершенно никакой высокоуровневой библиотечной поддержки; все, что мы имеем: coroutine_traits, coroutine_handle. И это, конечно, прекрасно: мы можем с помощью них писать свои сопрограммы. Однако не всем в удовольствие писать низкоуровневый код, хотелось бы иметь для прикладного использования и готовенькое.
И комитет не дремлет; в C++23 был принят пропозал (не реализованный еще ни в одном компиляторе):

1. 🇬🇧 std::generator: Synchronous Coroutine Generator for Ranges, описывающий корутинный генератор:

std::generator<int> iota(int start = 0) {
while (true)
co_yield start++;
}

void f() {
for (auto i: iota() | std::views::take(3))
std::cout << i << ' '; // Печатает 0 1 2
}

Кроме того, прямо сейчас в комитете рассматривается:

1. 🇬🇧 std::lazy: Coroutine for Deferred Execution, предлагающий довольно минималистичный класс для представления асинхронных вычислений:

lazy<int> coro() {
int result = 0;
while (int v = co_await async_read())
result += v;
co_return result;
}

void f() {
lazy<int> task = coro(); // Получим объект корутины
co_await task; // А теперь наконец ее исполним
}

К сожалению, далеко не факт, примут ли это предложение в C++26: как оно было подано в 2022-ом, так с тех пор и нет никакого прогресса в продвижениии к его принятию.

И на этом всё. Больше никакой поддержки в стандартной библиотеке пока что не предвидится. К счастью, уже написано несколько библиотек, предоставляющих помимо высокоуровневых корутинных примитивов средства для планирования (scheduling) задач и неблокирующего I/O:

1. 🇬🇧 Facebook: Folly::Coro — Асинхронный корутинный фреймворк от Facebook, быстрый и помимо всего поддерживающий асинхронные примитивы синхронизации.
2. 🇬🇧 Lewis Baker: CppCoro — Прародитель всех корутинных фреймворков. К сожалению, уже мертвый, но ввиду своей большой популярности продолживший жизнь через форки и многочисленных идейных продолжателей: [1], [2], [3], [4], [5].
3. 🇬🇧 Dan Vrátil: QCoro — Если вы хотите использовать в Qt корутины вместо сигналов.

А какие библиотеки используете вы? Или вы уже успели написать все самостоятельно? 😉
🔥6👍2
Вот и закончилась неделя корутин. Надеемся, наши материалы оказались не только интересны, но и полезны! И, так как это были первые посты в экспериментальном формате «Неделя X», мы приглашаем всех поделиться в комментариях своим мнением: понравился ли вам формат, как его можно было бы улучшить и какую неделю вы хотите видеть следующей послеследующей?

Кроме того, мы рады напомнить, что сегодня последний день приёма заявок желающих выступить с докладом на ближайшем митапе! А значит, следующая неделя будет неделей анонсов докладов C++ Moscow №2!
🔥6❤2
Чуть больше чем месяц остался до нашей встречи и мы рады познакомить вас с одним из запланированных докладов: Илья Быконя расскажет нам, как подружить Qt и корутины!
🔥6
Корутины и Qt. Библиотека QCoro

Qt появился уже почти 30 лет назад. Хотя фреймворк и сейчас поддерживается и получает крупные обновления как от разработчиков, так и от комьюнити, его событийно-ориентированная система заставляет нас использовать вереницы коллбеков или множество вложенных лямбд и на сегодняшний день выглядит достаточно громоздко в сравнении с другими языками и даже библиотеками C++ (привет, userver).

Библиотека QCoro призвана привнести возможности корутин в событийную систему Qt и позволить избежать описания лишнего кода, одноразовых функций и логики перекладывания данных из метода в метод.

Библиотека не ломает обратную совместимость. Все старые классы, по типу QNetworkManager, QFuture или классов IO-системы полностью совместимы с QCoro. Достаточно лишь заменить QObject::connect с коллбеком на co_await и узреть магию.

При этом библиотека надёжна и признана мировым сообществом. Например, она входит в официальные репозитории (extra) для Manjaro Linux, а значит, проходит несколько этапов проверок прежде, чем попасть в эти репозитории.
🔥9