С++17 і С++2a: новини із зустрічі ISO в Иссакуа

На початку листопада в американському місті Иссакуа завершилася зустріч міжнародної робочої групи 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;

З виправленим UA 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 конструктивні 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 поліномів». Тому що формула в розділі ну от не представима у вигляді полінома :-)

...Стандарт C++ — це серйозний міжнародний документ, який розробляється фахівцями з усього світу, в якому кожне слово має бути підібрано найбільш коректним чином і навіть незначні логічні протиріччя повинні бути виключені.

Від чого дана «шкільна» помилка посміхається мене ще сильніше :-)

Інше
  • 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<тип>
    . Особисто мені більше подобається минулий варіант. Але більшості, включаючи самого автора ідеї універсального тега, він перестав подобатися.
Обговорення та ідеї
Як завжди, обговорення і розбір помилок проходили в декількох підгрупах одночасно. Опинитися відразу в 5ти місцях — задача складна, так що всі ідеї переказати з перших рук не вийде. Ось найцікавіші обговорення, на яких ми побували:

??? operator.() ???
Обговорювали альтернативний синтаксис і підхід до operator.().
Старий синтаксис P0416R1 Новий синтаксис P0352R0
template < class X>
class Ref {
X* p;

public: 
explicit Ref(int a): p(new X{a}) {}
~Ref() { delete p; } 
operator. X&() { return *p; }
};


struct Y { Y(int); void f(); };
Ref<B> r {99};
r.f(); // (r.operator.()).f()


Y &yr = r; // ???

// O_O
static_assert(sizeof(Ref<B>) == sizeof(X)); 
template < class X>
class Ref : public using X {
X* p;
X operator&() { return* }
public: 
explicit Ref(int a): p(new X{a}) {}
~Ref() { delete p; }

};


struct Y { Y(int); void f(); };
Ref<B> r {99};
r.f(); // (r.operator Y&()).f()

// Error: conversion private function is
Y &yr = r; 

// Ref<B> constains only Y*
static_assert(sizeof(Ref<B>) == sizeof(Y*)); 
Іншими словами, пропонується замість operator.() використовувати кілька більш зрозуміле «спадкування, де про зберігання об'єкта класу автор дбає сам». WG21 попросила автора працювати далі в цьому напрямку.

operator<=>()
operator<=>() або «operator spaceship» — це ідея яка з'явилася з обговорення автоматичного генерування операторів порівняння. Комітет був проти того, щоб почати генерувати оператори порівняння за замовчуванням і проти того, щоб генерувати оператори порівняння з допомогою конструкцій виду bool operator<(const foo&, const foo&) = default;. Тоді в кулуарах народилася ідея:

  • Зробити оператор порівняння, відразу повертає значення less, equal, greater;
  • За наявності цього оператора — генерувати всі оператори порівняння;

Поки далі обговорення мова не заходила, але виглядає багатообіцяюче.

Reflections
Засідала група розробляє compile-time рефлексію для C++. У них є базовий функціонал, який вони вже майже готові передавати для подальшого обговорення в інші підгрупи і випускати у вигляді TS (technical specification) — доопрацювання до стандарту, з якої можна буде користувачам починати експериментувати, не чекаючи нової версії основного стандарту.

Підсумки
Люди на засіданні опрацювали величезну кількість коментарів до стандарту. Більше 100 недоліків було виправлено, за що їм величезне спасибі!

5ого грудня в Москві на зустріч Російської РГ21 ми чекаємо в гості Маршалла Клоу (Marshall Clow) — голови Library Working Group в WG21 C++ розробника стандартної бібліотеки libc++, автора Boost.Algorithm. На зустрічі ми розповімо про наші подальші плани і напрацювання, ви зможете задати питання по C++ і запропонувати свої ідеї для C++2a; Маршалл ж розповість про Undefined Behavior.

Ми також раді представити вам офіційний сайт робочої групи stdcpp.ru для обговорення ідей для стандартизації, допомоги в написанні proposals. Тепер ви зможете поділитися своєю ідеєю для включення в стандарт C++, дізнатися що про неї думають інші обговорювати запропоновані ідеї іншими розробниками. Ласкаво просимо!
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.