habrahabr

C++17, который мы потеряли

  • вторник, 29 марта 2016 г. в 03:19:19
https://habrahabr.ru/company/infopulse/blog/279927/
  • Совершенный код
  • Программирование
  • IT-стандарты
  • C++
  • Блог компании Инфопульс Украина



5-го марта 2016-го года в городе Джэксонвилл закончился очередной съезд комитета ISO C++. Люди собирались предварительно-окончательно решать, что же войдёт, а что не войдёт в стандарт С++17. Конечно, ещё не 2017-ый год и кое-что ещё, возможно, переиграется. Тем не менее, есть мнение, что именно данное мероприятие очертило С++17 в его будущем виде.

Я не буду тут тянуть кота за хвост и искать толерантные выражения: нас ждёт катастрофа. Стандарты С++11/14 были очень значительным скачком вперёд, но на этом всё закончилось. С++17, обещанный когда-то «мажорным» релизом, по факту не несёт в себе ничего существенного. Немного синтаксического сахара, пару мелочей в стандартную библиотеку — и на этом всё. Отголоски данной трагедии уже звучали некоторым эхо на Хабре, но я всё-таки решил обобщить информацию и понять, куда мы катимся.


Начнём с хорошего.

Что войдёт в С++17



Файловая система
Отличная штука! Была бы, если бы вошла в стандарт лет 15 назад. В самом деле, даже в богомерзком .NET классы для работы с файловой системой — с версии 1.1 (а это 2003 год). А тут вот руки дошли позаимствовать boost::filesystem в 2016-ом году. Ну и на том спасибо.

any, optional, string_view
Первые две штуки и так были доступны в разных библиотеках, string_view же выглядит как затычка, для тех, кто не освоил константные ссылки и shared_ptr. Третий способ сказать «вот тебе строка, которой ты не владеешь, можешь её только почитать». Ну ок, будет хорошо смотреться в интерфейсах, какого-то принципиального быстродействия по сравнению с двумя предыдущими способами не даст.

Лямбды в constexpr-функциях
constexpr int AddEleven(int n) {
return[n]{return n+11;}();
}
static_assert(AddEleven(5)==16,"");


Это вообще не столько желаемая фича, сколько приведение языка в консистентное состояние. Есть у нас лямбды, есть constexpr-функции, ну, видимо, должны быть и лямбды в constexpr-функциях. Дабы не рушить стройную картину мира. Ну хорошо. Лично я никогда не понимал программистов, пытающихся из этапа компиляции выжать всё настолько, как будто им рантаймом пользоваться запрещается, но почему бы и нет.

Параллельные алгоритмы
Да, это хорошо, что теперь какую-нибудь сортировку можно распараллелить «из коробки». Но с этой проблемой уже полтора десятка лет боролись все производители компиляторов, процессоров, основных фреймворков, и в общем-то на данный момент куда ни плюнь — так попадёшь или в Threading Building Blocks, или в один из десятка «Parallel STL», или в расширения языка вроде Intel Cilk Plus или ещё во что-то подобное. Кому был нужен параллелизм — у того был параллелизм. Более того, все библиотеки и фреймворки с выходом стандарта никуда не денутся, поскольку у каждого решения есть свои плюсы и они в них будут превосходить стандарт. Классическая ситуация «к 14-ти стандартам прибавился 15-ый»

Специальные математические функции
Что-что вы решили добавить в язык?! Сферические гармоники и гипергеометрические функции? Это вот прямо то, без чего каждый программист на С++ жить не может, по вашему? Ну боже мой, почему этому всему не нашлось места в какой-нибудь лежащей далеко в углу математической библиотеке, в бусте каком-то, в маткаде, в интеловских сдк, да где-угодно, кроме стандарта языка С++17?

С помощью ranged-for теперь можно бегать по диапазонам, в которых начало и конец имеют разные типы
Сейчас начало и конец диапазона должны быть одного типа (итерируемого). Для начала это и правда имеет смысл — мы ведь от него будем идти вперёд, это должен быть итератор. В то же время конец — штука неизменная, быть ему итератором совершенно не обязательно. Более того, иногда даже лучше иметь начало и конец двух принципиально разных типов, чтобы в виду отсутствия концептов можно было как-нибудь себя обезопасить от случаев «ой, я случайно скопипастил begin() дважды для указания диапазона».

Захват копии *this по значению в лямбдах
Ожидаемая фича. Передавать указатель на this можно было и раньше, но это не всегда было то, чего хотелось. Теперь можно и так, и так.

[[fallthrough]], [[nodiscard]], [[maybe_unused]]
Просто средства избежать ворнингов при компиляции. Код и раньше можно было организовать так, чтобы их не было. Причём я бы сказал, что и читабельность при этом удавалось сделать повыше, чем она будет теперь со всеми этими атрибутами.

Перейдём к плохому.

Что не войдёт в С++17



Концепты
Комитет сказал «не готово». Комитет сказал «давайте подождём ещё год или два». Я бы на их месте был более честен с людьми и сказал как есть: «а мы и не понимаем, как оно должно быть». Я не знаю как всё там в комитете варится внутри, но снаружи возня с концептами выглядит так, как будто каждый хочет их сделать для чего-то своего. Кому-то надо «чтоб было как typeclass в Хаскеле», кому-то хочется просто побольше ошибок компиляции и ворнингов, кто-то уже бредит новой шаблонной магией, кому-то невтерпёж наворотить архитектуру как у Звезды Смерти на базе нового функционала. В итоге лебедь, щука и рак тянут воз во все стороны с ожидаемым результатом.

Модули
Прекрасная фича! Блаженный рай избавления от инклюдов, инклюд-стражей, уменьшение зависимости от мерзкого препроцессора. Вот вы и услышали коротенькое описание того, чего не будет в С++17. Дело в том, что модули нынче существуют в виде старой (от 2012-го года) реализации в Clang и относительно новой реализации от Microsoft. Конечно же, они не совместимы между собой (кто бы сомневался), а комитет по стандартизации пока не может решить, кто ему милее. Отличаются реализации, окромя мелочей, принципиальной штукой — трактовкой понятия макроса внутри модуля. Принадлежит ли он модулю, или должен быть виден наружу? Оба подхода имеют плюсы и минусы, поэтому решить, какой брать, пока не могут. Поэтому всё будет наихудшим из возможных способов: в С++17 не будет вообще ничего, а вот в следующем стандарте, попомните моё слово, наверняка опять подожмут хвост и с тезисом «нам нужна обратная совместимость» выберут худшее архитектурной решение (экспортировать макросы).

Транзакционная память
Об этом пока рано говорить как-то всерьёз. Слишком ново, слишком революционно, надо мышление перестраивать. Правильно сделали, что не включили в стандарт.
int f()
{
  static int i = 0;
  synchronized {
    printf("before %d\n", i);
    ++i;
    printf("after %d\n", i);
    return i;
  }
}


Унифицированный синтаксис вызова
«Не было консенсуса для принятия». Прям как у депутатов, когда заходит речь о борьбе с коррупцией. И ведь предлагают его Bjarne Stroustrup и Herb Sutter. Кто же у них там в комитете настолько авторитетен, что может им аргументированно противостоять?

Дедуктивный вывод параметров шаблонов
Ну, чтобы можно было писать
pair p(2, 4.5);

вместо
pair<int,double> p(2, 4.5); 


Красивая штука! Но «пока не всё понятно». Для auto им, главное, правила вывода типов понятны, а для шаблонов — нет. С чего бы?

Networking
Шел 2016-ый год, а С++ о сетях слыхом не слыхивал. И до 2020-го года и не услышит теперь! И чего это, казалось бы, народ вон вокруг на Эрланги всякие переходит для обработки сетевых запросов? А потому что уважаемый С++ до сих пор не озаботился какой-никакой сетевой функциональностью из коробки. (Ну я утрирую, конечно, не только и не столько поэтому. Но за державу обидно.)

Сопрограммы
Эта история уже была на Хабре, не будем повторяться: habrahabr.ru/post/278267

Контракты (два варианта)
Эта штука совершенно до сего момента выпадала из моего поля зрения, а ведь классно:
auto function(ArgType1 arg1, ArgType2 arg2, ArgType3 arg3)
 [[ pre: arg1 != 0]]
 [[ pre: arg1 < arg2]]
 [[ pre: global_predicate(arg3) ]]
 [[ post: return > 0 ]]
 [[ post: other_predicate(return, arg1) ]]
 -> ResultType;


Можно проверить что-нибудь полезное на этапе компиляции, линковки, рантайме. Может помочь в ситуациях «решили передавать первым параметром всегда true, а не false и вроде бы везде(?) исправили вызов». Теперь уже на этапе компиляции можно будет сказать везде или не везде. Я не очень расстроен тем, что это не вошло в С++17, поскольку выглядит слишком уж неожиданно, требует обсуждения и доработки. В добрый путь!

constexpr if
Продолжаем перетягивать рантайм на этап компиляции. Хотя конкретно эта фича может быть вполне полезна, поскольку может изрядно сократить количество кода, построенного на шаблонах (см. примеры в доке).

Reflection
Шли годы, а разговоры о рефлексии в С++ всё продолжались. Сейчас на рассмотрении аж три подхода:

Но пусть меня покрасят, если хотя бы один из них войдёт в С++17. Даже на счёт стандарта 20-го года я бы сказал можно принимать ставки 50/50.

Что мы имеет в итоге


С++, конечно, не стоит на месте. Видно, что люди работают, документы пишутся, компиляторы развиваются. Но задор С++11 утерян. Это чувствует и сам комитет ISO C++. Они больше не называют С++17 мажорным релизом стандарта. Теперь это у них очередная рабочая лошадка, которая станет в строй по графику, будет предсказуема, послушна и не встанет на дыбы. Наверное, это то, что нужно большому бизнесу — стабильность. Но для среднего программиста большой целью перейти на 17-ый стандарт не будет. Никто не будет бить кулаком по столу проджект-менеджера с требованием перейти на новую студию, мало кто будет качать ночную сборку Clang чтобы посмотреть, наконец, на вот эту bleeding-edge функциональность 17-го стандарта. Комитет ISO C++ говорит, что это хорошо — мы можем планировать свою работу на годы вперёд. В каком-то плане, да, безусловно. Но перемены — это ведь так захватывающе. Дорогой-любимый комитет ISO C++, ну пожалуйста, не бойся напугать нас новыми фичами языка!
C++17?

Проголосовало 1217 человек. Воздержалось 519 человек.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.