В начале ноября в американском городе Иссакуа завершилась встреча международной рабочей группы WG21 по стандартизации C++, в которой участвовали сотрудники Яндекса. На встрече «полировали» C++17, обсуждали Ranges, Coroutines, Reflections, контракты и многое другое.
Заседания, как обычно, занимали целый день + решено было сократить обеденный перерыв на полчаса, чтобы успеть побольше поработать над C++17.
Несмотря на то, что основное время было посвящено разбору недочётов черновика C++17, успели обсудить несколько интересных и свежих идей и даже привнести в стандарт то, о чём нас просили на cpp-proposals@yandex-team.ru.
Разбор недочётов
Основная задача прошедшей (и следующей) встречи — разбор и исправление замечаний к C++17 (если вы не в курсе крупных нововведений C++17, то вам сюда). Замечания были двух типов: комментарии от стран-участниц WG21 и замечания от пользователей/разработчиков стандартной библиотеки. Комментарии от стран по традиции разбираются в первую очередь. Каждому комментарию присваивается идентификатор, состоящий из кода страны и последовательно возрастающего номера комментария. В этот раз пришло более 300 замечаний. Вот некоторые самые интересные и запомнившиеся из них:
RU 1: инициализация константных объектов
С 2000 годов в С++ есть проблема с инициализацией константных структур. Так, поведение компилятора внезапно зависит от ряда совершенно неочевидных факторов:
struct A0 {}; const A0 a0; // ошибка компиляции struct A1 { A1(){} }; const A1 a1; // OK struct A2 { int i; A2(): i(1) {} }; const A2 a2; // OK struct A3 { int i = 1; }; const A3 a3; // ошибка компиляции
Просьба исправить это поведение пришла к нам на cpp-proposals@yandex-team.ru от Ивана Лежанкина, мы с помощью людей из ГОСТ оформили его как комментарий от страны и… поведение исправили в C++14 и C++17. Теперь вышеприведённый код должен компилироваться.
Где это может быть полезно
Крайне полезно при рефакторинге. Раньше, удалив пустой конструктор, можно было сломать компиляцию проекта:
// в заголовочном файле: struct A1 { A1(){} // Если удалить, сборка проекта сломается }; // Код из проекта соседнего отдела const A1 a1;
С исправленным RU 1 можно будет менять классы, удаляя пустые конструкторы, и код продолжит работать. При этом можно получить небольшой выигрыш в производительности: библиотеки, использующие метопрограммирование, порой имеют дополнительные оптимизации для классов которые std::is_trivially_constructible; компиляторы зачастую лучше оптимизируют те конструкторы, которые они сами сгенерировали и т.д.
RU 2: невалидное использование type traits
Замечательный способ выстрелить себе в ногу, не заметить и умереть от потери крови:
#include <type_traits> struct foo; // forward declaration void damage_type_trait() { // Вызываем is_constructible для неполной структуры, что недопустимо. // Однако согласно стандарту именно пользователь должен проверять // валидность входных параметров, так что компилятор промолчит и скомпилирует код. std::is_constructible<foo, foo>::value; } struct foo{}; int main() { static_assert( // Выдаст неверный результат, компиляция функции damage_type_trait() // поломала std::is_constructible std::is_constructible<foo, foo>::value, "foo must be constructible from foo" ); }
Лично я потратил неделю, выискивая подобную ошибку в boost::variant. Теперь WG21 обратила внимание на проблему и работает над её исправлением. Есть все шансы на то, что в C++17 будет исправлено и компилятор, увидев код с инвалидным использованием type_traits, будет выдавать ошибку компиляции с сообщением, подробно описывающем причину проблемы.
Где это может быть полезно
Поможет вам не делать трудно обнаруживаемых ошибок. Избавит разработчиков от множества неприятных сюрпризов при использовании optional и variant, конструкторы которых используют type_traits.
RU 4 & US 81: constexpr char_traits
Мы и США нашли один и тот же недочёт. Проблема заключается в том, что std::string_view имеет constexpr конструктор, но инициализация объекта всё равно будет происходить динамически:
#include <string_view> // Ошибка компиляции: // > error: constexpr variable 'service' must be initialized by a constant expression // > constexpr string_view service = "HELLO WORD SERVICE"; // > ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // > string_view:110:39: note: non-constexpr function 'length' cannot be used // constexpr string_view service = "HELLO WORD SERVICE";
В качестве исправления приняли наш фикс (Была принята версия версия p0426r1, она пока не доступна для общего пользования).
Где это может быть полезно
Компилятор сможет лучше оптимизировать конструирование std::string_view, вы сможете использовать string_view в constexpr выражениях.
shared_ptr::unique()
Один из запросов был на то, что shared_ptr::unique() должен гарантировать синхронизацию памяти std::memory_order_acquire.
И тут мы поняли, что многие не знают, как правильно пользоваться этой функцией в многопоточной среде. Так вот, правильное использование — не пользоваться.
Если shared_ptr::unique() вернул true и ваша имплементация гарантирует std::memory_order_seq_cst, то… это ничего не значит! Ситуация может поменяться сразу после вызова функции unique():
- в другом потоке может быть ссылка на этот shared_ptr и он как раз сейчас копируется
- в другом потоке может быть weak_ptr который вызывает lock()
В итоге, решено было пометить метод unique() как deprecated и подробнее расписать все проблемы в описании shared_ptr::use_count().
Присоединённые полиномы функции Лежандра
Один запрос, пришедший к нам на cpp-proposals@yandex-team.ru из МГУ от Матвея Корнилова, нам особенно запомнился. В нём описывалось много интересных вещей, связанных с математикой. Некоторые идеи сейчас в разработке самим автором, а некоторые удалось отправить как «редакторские правки» к стандарту и исправить прямо на заседании в Иссакуа, поговорив с одним из редакторов стандарта.
Так вот, одна правка которая особенно запомнилась, заключалось в том, что надо переименовать раздел «Associated Legendre polynomials». Потому что формула в разделе ну вот не представима в виде полинома 🙂
От чего данная «школьная» ошибка улыбает меня ещё сильнее 🙂
Прочее
- std::variant не будет уметь хранить ссылки, void и C массивы (но вы всё ещё можете использовать std::reference_wrapper<T>, std::monostate и std::array чтобы добиться аналогичного поведения)
- продолжается работа над добавлением deduction guildes к стандартной библиотеке. Есть все шансы на то что
std::array a = "Hello word";
будет работать из коробки
- на заседание пришли специалисты по zOS с некоторыми замечаниями к std::filesystem. В планах — успеть на следующем заседании внести модификации в стандарт, чтобы сделать std::filesystem ещё более универсальным инструментом
- специальный «тег»
std::in_place<тип-данных-или-число>
возможно уберут в пользу нескольких тегов
std::in_place, std::in_place_index<число>, std::in_place_type<тип>
. Лично мне больше нравится прошлый вариант. Но большинству, включая самого автора идеи универсального тега, он разонравился.
Обсуждения и идеи
Как всегда, обсуждения и разбор ошибок проходили в нескольких подгруппах одновременно. Оказаться сразу в пяти местах — задача сложная, так что все идеи пересказать из первых рук не получится. Вот самые интересные обсуждения, на которых мы побывали:
??? operator.() ???
Обсуждали альтернативный синтаксис и подход к operator.().
Старый синтаксис P0416R1 | Новый синтаксис P0352R0 |
---|---|
|
|
Другими словами, предлагается вместо operator.() использовать несколько более понятное «наследование, где о хранении объекта автор класса заботится сам». WG21 попросила автора работать дальше в этом направлении.
operator<=>()
operator<=>() или «operator spaceship» — это идея которая появилась из обсуждения автоматического генерирования операторов сравнения. Комитет был против того, чтобы начать генерировать операторы сравнения по умолчанию и против того, чтобы генерировать операторы сравнения с помощью конструкций вида bool operator<(const foo&, const foo&) = default;. Тогда в кулуарах родилась идея:
- сделать оператор сравнения, возвращающий сразу значения less, equal, greater
- при наличии этого оператора генерировать все операторы сравнения
Пока дальше обсуждения речь не заходила, но выглядит многообещающе.
Reflections
Заседала группа, разрабатывающая compile-time рефлексию для C++. У неё есть базовый функционал, который уже почти готовы передавать для дальнейшего обсуждения в другие подгруппы и выпускать в виде TS (technical specification), доработки к стандарту, с которой можно будет пользователям начинать экспериментировать, не дожидаясь новой версии основного стандарта.
Итоги
Люди на заседании обработали огромное количество комментариев к стандарту. Более 100 недочетов было исправлено, за что им огромное спасибо!
Пятого декабря в Москве на встречу Российской РГ21 к нам приезжает Маршалл Клоу — председатель Library Working Group в WG21 C++, разработчик стандартной библиотеки libc++, автор Boost.Algorithm. На встрече мы расскажем о наших дальнейших планах и наработках, вы сможете задать интересующие вас вопросы по C++ и предложить свои идеи для C++2a; Маршалл же расскажет про Undefined Behavior.
А ещё мы запустили сайт stdcpp.ru для обсуждения идей для стандартизации, помощи в написании proposals. Там же вы сможете поделиться своей идеей для включения в стандарт C++ и узнать что о ней думают другие. Добро пожаловать!
ссылка на оригинал статьи https://habrahabr.ru/post/315606/
Добавить комментарий