company_banner

С++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;
    

    С исправленным 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». Потому что формула в разделе ну вот не представима в виде полинома :-)

    ...
    Стандарт 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<Y> r {99};
    r.f(); // (r.operator.()).f()
    
    
    Y &yr = r; // ???
    
    // O_O
    static_assert(sizeof(Ref<Y>) == sizeof(X)); 
    
    template<class X>
    class Ref : public using​ X {
      X* p;
      operator X&() { return* }
    public: 
    ​  explicit Ref(int a): p(new X{a}) {}
      ~Ref() { delete p; }
    
    };
    
    
    struct Y { Y(int); void f(); };
    Ref<Y> r {99};
    r.f(); // (r.operator Y&()).f()
    
    // Error: conversion function is private
    Y &yr = r; 
    
    // Ref<Y> constains only Y*
    static_assert(sizeof(Ref<Y>) == 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++, узнать что о ней думают другие и обсуждать предлагаемые идеи другими разработчиками. Добро пожаловать!
    Яндекс
    603,48
    Как мы делаем Яндекс
    Поделиться публикацией

    Комментарии 90

      +9
      Вот если бы меня спросили что надо улучшать в C++, я бы язык не трогал вообще. С языком все «норм». Нужно фиксить во-первых, либы т.к. STL — тихий ужас с точки зрения юзабельности (хотя обобщенные алгоритмы и выглядят корректно с точки зрения «обобщения» задач, их использование в 100 раз больнее чем, например, IEnumerable/LINQ). Нужен STL2 который будет сделан в стиле C#/Java — полные имена функций, удобоваримое преставление «перечисляемости» вместо пресловутых пар begin()/end(), вменяемые member functions, когда можно сделать `myvector.sort()` и не париться. Ну и STL нужно выводить на «бытовой» уровень — добавить например поддержку разных форматов (XML или PNG, например) из коробки, чтобы не надо было на каждый чих копать чужие сорцы, написанные во времена С.

      Вторая проблема — это скорость компиляции. Конечно, хорошо сиделать на Cling и получать REPL от Clang (даже если вы под Windows), но все же хочется и компилировать во вменяемые сроки. А модули могли уже сделать ой как давно, но че-то до сих пор тянут резину.

      В третьих, хочется чтобы закончились «пакетные войны» и С++ пришли к стандарту о пакет-менеджменте, даже если этот стандарт подразумевает локальную компиляцию. Rust эту проблему как-то решил, может решить и С++ если не пытаться делать из этого коммерческий продукт (привет, biicode) а просто зарелизить и хорошо пропиарить что-то работающее.

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

      • Extension methods, т.к. они проверены временем и реально нужны
      • Properties, т.к. они проверены временем и реально нужны
      • Дефолтные шортхэнды для лямбд, т.к. [](){} в большинстве случаев не надо. Также дефолтные параметры для аргументов лямбд ($0, $1, итд, привет Rust), возможность не писать [] (делая автоматов [=] для литералов вроде int32_t и [&] для всего остального, как собственно в C#), возможность не писать () если аргументов нет.


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



      Да и насчет spaceship operator — если надо чтобы простой класс определял весь пакет операторов и сразу, посмотрите на Котлиновский data class, это как раз то что нужно.

        +6
        Ну и STL нужно выводить на «бытовой» уровень — добавить например поддержку разных форматов (XML или PNG, например) из коробки, чтобы не надо было на каждый чих копать чужие сорцы, написанные во времена С.

        Поддерживаю целиком и полностью! Вам интересно будет начать писать proposal+прототип и прорабатывать эту идею в stdcpp.ru?

        Extension methods, т.к. они проверены временем и реально нужны

        Можете предложить синтаксис (здесь или на stdcpp.ru)?

        Дефолтные шортхэнды для лямбд, т.к. [](){} в большинстве случаев не надо. Также дефолтные параметры для аргументов лямбд ($0, $1, итд, привет Rust), возможность не писать [] (делая автоматов [=] для литералов вроде int32_t и [&] для всего остального, как собственно в C#), возможность не писать () если аргументов нет.

        () можно уже давно не писать.

        «автоматом [=] для литералов вроде int32_t и [&] для всего остального» — ночной кошмар при отладке, суровая возможность убить себе производительность. Лично я очень не люблю [=] и [&], пожалуйста не надо делать их использование ещё проще.
          +3
          Одна из самых больших болей в с++ c которой сталкивался, это использование в каждой более-менее большой библиотеке своих строк, своих типов для Vector3, Matrix4x4, отсутвие возможности в std сделать конвертацию cp1251 -> utf8 и обратно, необходимость всегда первым делом тащить в проект libpng, libjpg, libzip и прочее что уже стало неким стандартом, по хорошему я бы пол Qt в stdlib запихнул, особенно по части работы с форматами мультимедия. это даже более важное чем модули, которые кстати то же нужны, на с++ сейчас смешно без этого смотреть.
            0
            У меня нет большого опыта конвертации кодировок, работы с libpng и libjpg. Если у вас есть идеи о том, как правильно их внедрить в стандарт — пишите обязательно, постараюсь по максимуму вам помочь.

            Vector3, Matrix4x4 — над подобными типами данных работают, но я не в курсе прогресса по ним. В C++17 их точно не будет.
              0
              необходимость всегда первым делом тащить в проект libpng, libjpg, libzip и прочее что уже стало неким стандартом… это даже более важное чем модули


              А почему нельзя ввести модули и оформить вышеописанные библиотеки как модули, которые было бы легко подключать?

              Часть этих проблем, кстати, отсутствует, если писать под Windows (да, готов принимать помидоры за это утверждение). Изображения открываются через GDI+ абсолютно простыми и понятными методами. В WinAPI присутствуют функции для работы со строками с преобразованием CP??? <-> UTF-8 <-> UTF-16, есть CompressionAPI для работы с zip.

              Отличие же libpng, libjpg и т.д. заключается в том, что они являются самостоятельными библиотеками, а не частью API операционной системы. Хорошо это или плохо — ответ неоднозначаный: хорошо, потому что отвязываемся от реализации в конкретной ОС, плохо — тащим с собой кучу кода, имеем проблемы с его подключением.
                0
                В WinAPI присутствуют функции для работы со строками с преобразованием CP??? <-> UTF-8 <-> UTF-16

                нормальный API для работы со строками должен как минимум принимать на себя задачи по управлению памятью.
                  +1
                  И для DistortNeo тоже

                  В принципе особенных проблем с конвертацией сейчас нет, особенно из юникода в юникод.
                  #include <locale>
                  #include <codecvt>
                  
                  using namespace std;
                  
                  static wstring m_message_string;
                  static wstring_convert<codecvt_utf8_utf16<wchar_t>> m_converter;
                  //---------------------------------------------------------------------------
                  inline wstring to_wstring(const string& p_text)
                  {
                  	return m_converter.from_bytes(p_text);
                  }
                  //---------------------------------------------------------------------------
                  inline string to_string(const wstring& p_text)
                  {
                  	return m_converter.to_bytes(p_text);
                  }
                  


                  P.S. просто скопипастил реализацию из своего проектика, на спецификаторы внимания не обращайте ;) С ANSI строками будет чуть сложнее, но задача тоже решаемая.
                0

                А какую библиотеку лучше взять libjpeg, libjpeg-turbo или mozjpeg? Если запихнуть Qt в stdlib, то как часто мы будем получать новую версию? За 4 года Qt поменял версию с 5.0 до 5.7.

                  0
                  во-первых, Qt в stdlib никто запихнуть не сможет. Во-вторых, чего вам не хватает в Qt 5?
                    0

                    Я не говорил, что мне чего-то не хватает в Qt. Факт то что Qt постоянно развивается и версии выходят чаще, чем новые стандарты.

                  0
                  отсутвие возможности в std сделать конвертацию cp1251 -> utf8 и обратно

                  В принципе при использовании std::locale и в целом Localization library уже сейчас можно спокойно написать конвертор для более простого конвертирования из ANSI локали в нужный UNICODE и обратно и внести его в стандарт, проблемы то нет особо. Там не особо большие изменения требуются.
                  0
                  Я написал большое полотно но кнопка «Опубликовать» на сайте делает ровно ничего :(
                    0
                    Пожалуйста, напишите в личку, каким браузером пользуетесь, ОС и вышлите пожалуйста принтскрин.
                  +4
                  Нужно фиксить во-первых, либы т.к. STL — тихий ужас с точки зрения юзабельности

                  Ranges требует concepts, что требует изменений самого языка.


                  Extension methods, т.к. они проверены временем и реально нужны

                  Был пропозал с соавторством аж самого Страуструпа про unified call syntax.


                  Также дефолтные параметры для аргументов лямбд ($0, $1, итд, привет Rust)

                  А что это?


                  возможность не писать [] (делая автоматов [=] для литералов вроде int32_t и [&] для всего остального, как собственно в C#)

                  Пахнет выстрелом в ногу, особенно с такими правилами.


                  Как должен захватываться class Foo { int32_t member; };? class Foo { int32_t member [1]; };? class Foo { int32_t member [1000]; };?


                  возможность не писать () если аргументов нет

                  Можно аж с C++11 (если только вам не нужно указать mutable).

                    +7
                    Не могу согласиться по поводу «боли» от использования STL. vector.sort() — это, конечно, несколько более лаконично, вот только если вдруг вам понадобится отсортировать не весь вектор, так сразу почувствуется вся неуниверсальность такого подхода. Я уже молчу о, например, совместимости с C-массивами, которые пока что из стандарта никуда не делись, да и вряд ли денутся.

                    Сахар в духе Properties, конечно, неплох, но не так уж он и нужен. Никто не запрещает вам иметь get/set методы. Extension методы вообще относительно спорная штука.

                    Есть куча других нужных вещей, которых еще нет, я не спорю. Но добавление нового способа делать то, что и так уже нормально работает из коробки — это ИМХО, не должно быть приоритетом.
                      0
                      Сахар в духе Properties, конечно, неплох, но не так уж он и нужен. Никто не запрещает вам иметь get/set методы.

                      Да, но таки меня вот, например, иногда критикуют за то что я, вынужденно, использую для генерации get/set методов и ещё много где для генерации кода макросы. Properties и прочий синтаксический сахар эту проблему решили бы и для меня и для всех критикующих тоже :)

                      Собственно у меня проблем нет и Properties мне не сильно нужны, но приходиться писать как то так иногда:
                      #define SETTINGS(name, dev, min, max, def, type)\
                        static CONST type dev##name##Min = min;\
                        static CONST type dev##name##Max = max;\
                        static CONST type dev##name##Default = def
                      
                      
                      #define VER_MIN_S(value, dev)\
                        if (value < dev##value##Min)\
                          value = dev##value##Default
                      
                      
                      #define VER_MIN(value)\
                        if (value < value##Min)\
                          value = value##Default
                      
                      
                      #define VER_MAX_S(value, dev)\
                        if (value > dev##value##Max)\
                          value = dev##value##Default
                      
                      
                      #define VER_MAX(value)\
                        if (value > value##Max)\
                          value = value##Default
                      
                      
                      #define VERIFI_S(value, dev)\
                        if (value < dev##value##Min || value > dev##value##Max)\
                          value = dev##value##Default
                      
                      
                      #define VERIFI(value)\
                        if (value < value##Min || value > value##Max)\
                          value = value##Default
                      
                      
                      #define VER_MIN_EXCL_ZERO(value)\
                        if (value != 0 && value < value##Min)\
                          value = value##Default
                      
                      
                      // TODO
                      #define GETSET(type, name, name2)\
                        private: type name;\
                        public: /*TODO TypeTraits<type>::ParameterType*/ type get##name2() const { return name; }\
                        void set##name2(/*TODO TypeTraits<type>::ParameterType*/ type a##name2) { name = a##name2; }
                      
                      
                      #define GETSETBASE(type, name, name2)\
                        protected: type name;\
                        public: /*TODO TypeTraits<type>::ParameterType*/ type get##name2() const { return name; }\
                        void set##name2(/*TODO TypeTraits<type>::ParameterType*/ type a##name2) { name = a##name2; }
                      


                      У многих это вызывает БООООЛЬ ;)
                        0
                        P.S. «CONST» это не опечатка это тоже вынужденная мера поскольку код используется сразу на нескольких сильно разных платформах, одна из которых вообще микроконтроллер и там очень тяжко с ресурсами и местами сильно плохо в целом, typedef не спасает ибо не везде работает и в итоге там вот такое безобразие:
                        ...
                        
                        #define CONST const
                        ...
                        
                        #define CONST __flash
                        
                        ...
                        


                        Такой вот он IoT :)
                        0
                        Ну и STL нужно выводить на «бытовой» уровень — добавить например поддержку разных форматов (XML или PNG, например) из коробки, чтобы не надо было на каждый чих копать чужие сорцы, написанные во времена С.

                        Мало библиотек сорцами времен C++11?

                          +2
                          Есть ли пример «проверенного» SAX XML парсера на C++11?
                            0
                            Присоединяюсь к вопросу eiskalt, покажите, пожалуйста, пример библиотеки для работы с XML, или любыми форматами картинок на C++11 ибо всё мне известное использует либо C++03/98 либо вообще голый C с интерфейсами C++03 :(

                            P.S. искать мне не лень и самому, но я уже давно не могу найти работающую замену старым решениям, к сожалению.
                            0
                            привет, biicode

                            Есть такой проект, от создателей biocide: conan.io. Вроде интересен сам по себе: не зависит от системы сборки, неитрузивный, можно поднимать локальный репозиторий. Но репозиторий почти пуст, коммитят в них полтора человека, да и те — авторы проекта. Непонятно, будет он жить, или нет (вроде, обещают интеграцию с Artifactory), но с технической точки зрения — штука интересная.

                              +1
                              Выглядит многообещающе. Но вот у одной компании есть NuGet, и отказываться от него они не собираются.

                              Нужно чтобы conan.io научился работать с NuGet, а NuGet с conan.io. Тогда, наверное, проблемы со стандартизацией будут решаемые.
                                +1

                                NuGet больше для C#, а для плюсов — vcpkg.

                                  0

                                  Да, vcpkg выглядит хорошо — как apt-get для Windows.
                                  Вот сравнение с NuGet и Conan.io

                                    0

                                    Ну на первый взгляд он выглядит так, будто его не проблема и на линуксе завести, хотя использовать для описания пакетов cmake немного странно выглядит, но с другой стороны это должно как-то легко приделываться к любому другому cmake проекту.

                                      0

                                      Нет, оно там гвоздями к винде приколочено, разрабатывалось без оглядки на другие ОС (а жаль, имхо, оно лучше, чем conan)

                                        0

                                        Приколотить гвоздями к винде cmake нужно еще постараться, он же crossplatform. Таланты блин)

                              0
                              Язык уже превратился в такой ком костылей и всего прочего, что нужен просто другой язык. А stl надо не просто фиксить, а очень быстро развивать, ибо грызть этот кактус становится уже больно.

                              >> Extension methods
                              Поиспользовал в C#, уже нет особого желания их использовать, особенно когда в них начинают пихать нереальных размеров всякий бред, сложную логику и работу с БД. С одной стороны полезно, в комбинации с адекватными лямбдами можно сделать без боли в одном месте аналог linq (C#) и streams (Java), но по ощущениям не самая важная вещь. Уж лучше asio перетащить в stl, пользы будет больше, да хотя бы boost::di докинуть.

                              >> Properties, т.к. они проверены временем и реально нужны
                              Я бы сказал, хорошо там где нас нет. Пожив в C#, почитав Рихтера, пришло понимание, что может быть данная концепция и удобна, но постоянные злоупотребления приводят к очень неприятным последствиям. Меняете свойство, ожидаете одно поведение, а ловите непонятно что. То дедлок, то эксепшен, то меняются другие свойства, то еще куча всего. В итоге я бы не стал трогать, кому надо, тот сделает себе эти самые свойства существующими средствами языка.

                              Лямбды, надо смотреть в сторону других языков, я не понимаю, зачем надо описывать захваты, если в большинстве случаев можно определить из контекста. $0, $1 вот не надо такого счастья, не могу ничего доброго вспомнить о Perl с его невообразимой куче всяческих переменных такого вида. Разбираться в таком коде и врагу не пожелаешь.
                                +3
                                Лямбды, надо смотреть в сторону других языков, я не понимаю, зачем надо описывать захваты, если в большинстве случаев можно определить из контекста.

                                Мне кажется что в большом количестве случаев, определить из контекста невозможно:
                                int a = 0;
                                int b = some_value();
                                auto f = [?a, b]() mutable { 
                                    ++b;
                                    a += b;
                                    std::cout << a;
                                };
                                
                                if (something()) {
                                    ++a;
                                }
                                f();
                                

                                Хотел тут пользователь передать «a» по ссылке или по копии? Формализовать логику копия/ссылка будет очень тяжело, она может значительно замедлить компилятор и приводить к не очевидному поведению.
                                  0
                                  Поиспользовал в C#, уже нет особого желания их использовать

                                  Я их использую как альтернативу плюсовому функционалу по специализации шаблонов.
                                  И очень не хватает перегрузки операторов в C# для дженериков: почему extension-методы допустимы, а перегрузки операторов (суть то же самое) — нет?
                                  +2
                                  По моему Properties уже давно успешно реализуются через темплейты.
                                  Extension methods конечно хорошо, но затруднит читаемость кода.
                                  Ну а с лямбдами всё спорно, изначально у них странный синтаксис. Меня всегда особенно беспокоил возвращаемый тип через '->', это уж совсем как-то мерзковато.

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

                                  и его не будет тошнить от неудобоваримости увиденного

                                  Ну это очень спорно. Когда уже долго пишешь на плюсах его синтаксис начинает казаться идеалом.
                                    –3
                                    По-моему, нужен просто новый удобный диалект C++, который был бы семантически идентичным C++, но синтаксически несовместимым с ним. Все проблемы растут от того, что C++ прирастал костылями, вместо того, чтобы перерасти в новый язык.

                                      0
                                      Так может тогда проще писать на C#?
                                        0
                                        Так я и пишу на нём. На C++ переключаюсь только для написания вычислительного кода (обработка изображений).
                                      +3
                                      Ну а с лямбдами всё спорно, изначально у них странный синтаксис.

                                      у них лаконичный синтаксис
                                      Меня всегда особенно беспокоил возвращаемый тип через '->', это уж совсем как-то мерзковато.

                                      а в чем проблема? Во многих яп используется такой синтаксис. Особенно с учетом того, что в большинстве случаев указывать тип возвращаемого значения не нужно.
                                      Ну это очень спорно. Когда уже долго пишешь на плюсах его синтаксис начинает казаться идеалом.

                                      едва ли идеалом, но полный контроль над происходящим — то, к чему привыкаешь и чего в большинстве языков нет и никогда не будет.
                                      0
                                      • Дефолтные шортхэнды для лямбд, т.к. [](){} в большинстве случаев не надо. Также дефолтные параметры для аргументов лямбд ($0, $1, итд, привет Rust), возможность не писать [] (делая автоматов [=] для литералов вроде int32_t и [&] для всего остального, как собственно в C#), возможность не писать () если аргументов нет.


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

                                      Мне кажется что при наличии таких брёвен (возможно объективно неизбежных) как нотация шаблонов, смысл которых в конечном итоге получается как раз в попытке привнести техники функционального программирования в C++ говорить об улучшении синтаксиса лямбд по большому счету похоже на вычищение соринок.
                                      Но это так к слову. Главное что, вот всё-таки это всё больше похоже на предложения по введению синтаксического сахара (причем достаточно субъективного с т.з. пользы), чем на улучшения в языке. И ставить в зависимость от него введение новых фич мне кажется неправильно.


                                      Если говорить и приглашать к предложению новых идей для C++, то при организации всего этого стоит четко представлять себе ценность, мотивацию и место, которое занимает то или иное предложение с инженерной точки зрения — это либо исправление логической несогласованности и снятие искусственных ограничений как примеры в статье, либо действительно полезная для разработки фича, уточнение базовых идей, которое делает язык идейно простым и понятным (в качестве самого показательного примера можно привести новые правила генерации специальных функций-членов класса), либо же это очередная претензия студента к тому, как надо записывать лямбды, чтобы они смотрелись красиво (или по привнесению каких-то ещё как они любят выражаться "вкусных плюшек" из других знакомых языков: C#, Pyton, Rust чтоб было так же "удобно" и "круто"), либо какой-нибудь синтакическо-семантический хак для реализации некой красивой идеи, либо ещё что-то. В общем каждый, кто имеет опыт участия в обсуждении предложений по "улучшению" какого-либо языка программирования наверняка может представить во что всё это может выливаться. :)

                                      +1
                                      нет модулей — не нужно
                                        0
                                        поясните, пожалуйста
                                          0
                                          Избавиться от отстрелов всех частей тела с раздельными .cpp и .h файлами.
                                            0
                                            Не хочу вас расстраивать, но модули это не лечат.
                                              0
                                              Я и не сказал, что файлы сольются в кучу, это привело бы к тому, что компилироваться стало бы всё куда медленее. По крайней мере отстрела конечностей будет меньше.
                                            –1
                                            Нужно избавиться, наконец, от рудимента с разделением на h и cpp:

                                            1. Независимая трансляция каждого cpp-файла сильно замедляет процесс компиляции, особенно если используется большое количество инклюдов и шаблонного кода. Компиляция должна быть на уровне проекта, а не файла.

                                            2. Сложность с подключением библиотек: статические библиотеки не являются самодостаточными, их нельзя просто взять и подключить, как в других языках. Изволь тянуть с собой кучу инклюдов и не забывать прописывать пути.

                                            Но я сомневаюсь, что здесь будут подвижки. Переход на модули, например, поломает частичную специализацию шаблонов и кол, использующий директивы препроцессора. Это потребует переписывания всей стандартной библиотеки. Получится, фактически, не надстройка над C++, а новый язык.
                                              +13
                                              Давайте я вкратце и упрощённо распишу, как работают модули и что именно «тормозит при компиляции»:

                                              Когда вы собираете проект, каждый cpp файл может компилироваться параллельно (это хорошо, отличная масштабируемость).

                                              Однако, как правило, вы используете одни и те же заголовочные фалы в каждом cpp файле. За счет того, что компиляция различных cpp фалов никак не связана друг с другом, при каждой компиляции компилятор разбирает одни и те же заголовочные файлы… снова… и снова… Именно этот разбор и тормозит (заголовочный файл iostream весит более мегабайта, подключите 20 подобных заголовочных файлов — и компилятору придётся просмотреть и разобрать около 30 мегабайт кода при компиляции одного cpp файла).

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

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

                                              И наконец, финальная стадия сборки проекта — линковка. В данный момент линковщик много времени тратит на выкидывание одинаковых блоков скомпилированного кода (вы подключили iostream 100 раз — линкер выкинет 99 скомпилированных std::cout). С модулями есть шанс, что линкеру не придется этим заниматься, т.к. файл модуля не будет вкомпиливаться внутрь собранного cpp файла.

                                              Модули ничего не ломают, иначе бы их не принимали в стандарт. Модули не будут автоматически генерироваться для вашего проекта. Вам придется постараться и описать публичные интерфейсы модуля, чтобы получить дополнительные плюшки модулей.
                                                0
                                                Ух ты! Какой большой ответ для человека который не понимает как устроен c++.
                                                Еще можно добавить про precompiled headers на «используется большое количество инклюдов и шаблонного кода».
                                                  0
                                                  Да, именно этим и занимались линковщики в 80-90-е годы, бездумно собирая программу из предоставленных объектных модулей. Сейчас же линковщик делает то же самое, что и компилятор — оптимизирует код: основное время линковщика тратится не столько на выбрасывание дублирующегося кода, сколько на межпроцедурную оптимизацию для программы целиком.

                                                  С помощью g++ можно, например, компилировать программу как единое целое, минуя создание объектников.
                                                    +4
                                                    Межпроцедурную оптимизацию делает не линкер, а компилятор, который вызывается из линкера.

                                                    С помощью g++ можно, например, компилировать программу как единое целое, минуя создание объектников.

                                                    Если вызвать «g++ -flto file1.cpp file2.cpp», то объектники всё-равно создадутся (в /tmp), потом подадутся линкеру, и он опять позовёт gcc для перекомпилиции с межпроцедурными оптимизациями. Можно подать опцию -v и увидеть все подробности.
                                                      0
                                                      Да, именно этим и занимались линковщики в 80-90-е годы

                                                      И продолжают заниматься по сей день. Было бы неплохо, чтобы эта часть сборки происходила ещё быстрее :)
                                              0
                                              offtop: Как человек, живущий в Иссакве, прошу — поменяйте спеллинг, пожалуйста
                                                0
                                                Два различных поисковика утверждают, что писать надо «Иссакуа» :(
                                                  0
                                                  В англоязычной википедии есть произношение (фонетический алфавит) — оно скорее «Исэква». Ну да ладно =)
                                                  0
                                                  Хе-хе я тоже там живу :)
                                                  И да, среди русско-говорящих принято называть «Иссаква»
                                                  +3
                                                  Заканчивался 2016 год, а в STL так и нет ВООБЩЕ НИЧЕГО для кроссплатформенной работы с сокетами. И видимо ещё лет 6 не будет… Будем надеяться что хоть filesystem не выкинут туда же.
                                                    +2
                                                    Networking в течение года должен появиться в виде TS (уже отправлен на утверждение его черновик). Сможете воспользоваться кроссплатформенными сокетами ещё до C++2a (возможно что даже до C++17).
                                                      0

                                                      А мне вот отвратительно видеть, что в этом пропозале форсируется использование паттерна проактор (по сути весь Asio, как есть), тогда как на том же Linux/FreeBSD да и вообще всех Unix — реактор реализуется меньшими накладным расходами.


                                                      Т.е. моё мнение, что код для сокетов должен быть оторван от асинхронности. Абстракция над сокетами — отдельно. Асинхронная работа — отдельно. И вот тут бы было неплохо иметь возможность выбора стратегии.


                                                      Сама абстракция над сокетами же, работа с параметрами сокетов — мне нравится. Даже можно выпендриться и использовать только её, скрестив, допустим, с libev: когда игрался получился заметный выигрыш в попугаях на стендовом http сервере.

                                                      0
                                                      Я бы написал ещё жёстче: в STL до сих пор нет средств для кроссплатформенной работы с файлами в целом, а не только с сокетами.

                                                      Ну а что касается сокетов: не хочется жертвовать производительностью ради универсальности. В драфтах, например, не планируется использование ни epoll, ни IO completion ports.
                                                        0
                                                        Ну filesystem уже в TS, если что. В VS как минимум уже можно пользоваться.
                                                          0
                                                          Файловая система в C++17

                                                          В драфтах, например, не планируется использование ни epoll, ни IO completion ports.

                                                          Мы точно про одни и те же драфты говорим?
                                                            0
                                                            Мы точно про одни и те же драфты говорим?

                                                            Не знаю. Я вот этот драфт имел в виду:
                                                            http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4612.pdf
                                                              +3
                                                              В нём нет текста, запрещающего использование epoll или IOCP. Платформо специфичные вызовы не описываются в стандарте. Так например вы не найдете CreateThread в описании std::thread.

                                                              Драфт Networking основан на ASIO, активно разрабатывался тем же разработчиком и ASIO является прототипом к TS. Можете посмотреть на реализацию ASIO, и там вы найдёте использование epool, pool, select, iocp (в зависимости от платформы).
                                                                0

                                                                Причём максимально эффективно работает только iocp ;-)

                                                            +1
                                                            не планируется использование ни epoll, ни IO completion ports.

                                                            я или что-то не то смотрел, но нетворкинг это практически Asio как есть. epoll/IOCP это детали реализации. Ну а то, что оверхеда с epoll больше за счёт эмуляции проактора на реакторе — это архитектурный прогиб под IOCP.

                                                          –7
                                                          Хватит захламлять язык!
                                                          из-за ваших стандартов пришлось перейти на C# как на более стабильный стандарт C++ :p
                                                            +3
                                                            А чего ж не на ржавчину сразу?
                                                              –2
                                                              Если вы смогли просто перейти на другой язык, то С++ вам никогда и не нужен был ;)
                                                              +2
                                                              Раз уж зашла речь о предложениях, меня всегда интересовало, почему функции std::uninitialized_copy/fill/move не имеют перегрузок, которые принимают аллокатор как дополнительный параметр. Раз уж они внутри всё равно вызывают placement new, почему не сделать перегрузку, которая вместо этого вызывает allocator_traits::construct?
                                                                0
                                                                Похоже на дефект. Поузнаю поподробнее, возможно что к C++2a поправим.

                                                                Спасибо!
                                                                  +1
                                                                  И как?
                                                                    0
                                                                    Поузнавал.

                                                                    Планов по тому чтобы пометить allocator::construct как deprecated нет. Люди не очень любят аллокаторы, но согласны что эти функции должны его принимать. Так что стоит написать proposal на добавление перегрузок принимающих Allocator.

                                                                    Опишите вашу идею на https://stdcpp.ru/proposals чтобы она не потерялась и чтобы можно было собрать отзывы. Как будете готовы — всячески помогу с написанием proposal.
                                                                0

                                                                Лучше бы вместо костылей в виде оператора <=> запилили аналог derive из раста, решило бы ВСН проблемы с автоматической генерацией операторов.

                                                                  0
                                                                  Опишите пожалуйста вашу идею поподробнее. Чем это лучше?
                                                                    0

                                                                    Да хотя бы очевидностью процесса: если нам нужен конструктор копирования или операторы сравнения, то мы пишем #[derive(Clone, ParialEq)] и они только в этом случае генерируются. Эту идею можно совместить с концептами и все операторы выразить через них, а также много чего еще, к примеру обозначить уровень потокобезопасности класса или сгенерировать для него автоматически методы для сериализации/десериализации его полей.

                                                                  +3
                                                                  Ну когда уже в C++ интегрируют Брайнфак, я устал ждать…
                                                                    +2
                                                                    Надеюсь вы предлагаете Брейнфак, выполнимый на этапе компиляции!

                                                                    Давайте уж лучше сделаем Java(слишком скучно), C#(слишком мейнстрим), Erlang (не модно), Node.js (hype спал, оно ещё живо?) Rust на шаблонах. В конце концов, надо успеть отдать должное этому языку, прежде чем он канет в Лету.</troll-mode>
                                                                    0
                                                                    Интересно, когда появится constexpr new (для создания constexpr — объектов, мутабельные версии которых используют кучу)?
                                                                      0
                                                                      Я прям хочу этот функционал! Но международный комитет, как мне кажется, пока к нему не готов :)
                                                                      Надо сначала разрешить виртуальные функции в constexpr выражениях и подкрутить правила работы с деструкторами в constexpr выражениях.
                                                                      0
                                                                      Товарищи, просветите, кто-нибудь: вот раньше при работе с последовательностями данных, по которым мне достаточно проитерироваться, я обычно писал функцию, принимающую пару итераторов: начало и конец (ну еще iterator_tag нужный требовал через enable_if) для того, чтобы можно было передать содержимое любого контейнера (или вообще читать через input_iterator). А сейчас у нас итераторы, я так понял, deprecated, а range еще не введены.
                                                                      Какой православный метод предполагается в данном случае?
                                                                        0
                                                                        А сейчас у нас итераторы, я так понял, deprecated
                                                                        Да нет, с чего бы?
                                                                          +2
                                                                          Deprecated только вспомогательный класс std::iterator. Этим классом сложно пользоваться (я например не помню, в каком порядке передавать шаблонные параметры) и он бесполезен при написании шаблонных итераторов.

                                                                          Остальные итераторы никто не трогал, ими всё ещё можно (и нужно) пользоваться.
                                                                            +1
                                                                            Понятно, у меня было неверное понимание. Спасибо
                                                                          0
                                                                          Лучше бы стандартизировали декораторы имен (или что там мешает использованию классов в dll) и шаблонов там же. Впрочем, уже 3 года на C# сижу и не жалею.
                                                                            0
                                                                            Всякие Properties и Extensions вещь конечно нужная, но жить без них вполне можно. И как уже было сказано выше, те же Properties реализуемы текущими средствами языка, кому нужно, тот допишет.

                                                                            А вот поддержка UNICODE из коробки, так чтобы fopen (понятно, что он еще из C, но ведь из C++ никуда не делся), да что там, fstream::open принимал UTF8 на всех платформах, а не только на UNIX.

                                                                            Хотелось бы, что-бы std::string умел работать с UNICODE, без проблем поддерживал композицию/декомпозицию и банальное сравнение без учета регистра (с учетом текущей локали), и поиск по строке (естественно с учетом разных форм записей одной и той же строки в UNICODE).

                                                                            И после Objecive-C с их подсчетом ссылок, std::enable_shared_from_this кажется жесточайшим костылем. Я понимаю, что RAII важная и удобная концепция языка (чего не хватает многим java/C#/JS), но есть 2 проблемы:
                                                                            — как быть, если объект с std::enable_shared_from_this создается на стеке?
                                                                            — в целом хранение счетчика ссылок «далеко» от самого объекта существенно снижает производительность.

                                                                            Я бы предложил создавать счетчик прямо в объекте (так быстрее и не нужны костыли), и запретить создавать такие объекты на стеке, еще на этапе компиляции!
                                                                              0
                                                                              Хотелось бы, что-бы std::string умел работать с UNICODE, без проблем поддерживал композицию/декомпозицию и банальное сравнение без учета регистра (с учетом текущей локали), и поиск по строке (естественно с учетом разных форм записей одной и той же строки в UNICODE).

                                                                              Да, это известные проблемы и над ними работают.

                                                                              — как быть, если объект с std::enable_shared_from_this создается на стеке?

                                                                              Просто не позволяйте так делать:
                                                                              class foo: public std::enable_shared_from_this<foo> {
                                                                                  foo() = default;
                                                                              public:
                                                                                  static std::shared_ptr<foo> construct();
                                                                              };
                                                                              


                                                                              — в целом хранение счетчика ссылок «далеко» от самого объекта существенно снижает производительность.

                                                                              std::make_shared решает эту проблему. Везде и всегда его используйте!
                                                                              0

                                                                              Дайте аналог realloc. Хотя бы для простых, POD и trivially_copyable типов.


                                                                              Не знаю, пусть будет хотя бы так:


                                                                              new_ptr = new (old_ptr) Foo[new_size];

                                                                              Для сложных типов вполне себе может быть сэмулирована как new[]/move/delete[].


                                                                              Сигнатура для оператора может быть (что бы не конфликтовать с placement new):


                                                                              void* operator new (size_t size, void *old_ptr, struct realloc_tag);

                                                                              Такой синтаксис сейчас применим для placement_new с массивами, но может вызывать проблемы. Оно и понятно: особенно для non-POD нужно хранить где-то количество элементов, что бы конструкторы вызвать.


                                                                              Поддержка со стороны языка нужна так как оператор ничего не знает о типах, он просто выделяет память. А уже операиця new, должна решить, в зависимости от типа: делать realloc или new/move/delete. Ну и ограничить применимость только для массивов, так как я слабо представляю необходимость такой процедуры для единичного элемента в памяти.

                                                                                0
                                                                                так он по факту нужен для реализации контейнеров. А для общего назначения у нас всякие std::vector/std::string/… уже есть.
                                                                                  0

                                                                                  Да, я согласен. Но иногда в тесных рамках embedded бывают ограничения на использование STL. Собственно там как раз такое и сильно треба бывает.

                                                                                    0
                                                                                    тут уж как говорится «проблемы индейцев вождя не волнуют». Плюс, насколько я знаю, в контроллерах не комильфо выделять память через new.
                                                                                      0

                                                                                      Контроллеры бывают разные: между AVR8 и PIC и Rapberry PI пространства очень много и оно далеко не пустое. Так что и аллокации в куче бывают нужны/позволительны. А вот ограничения на использование STL бывают, нередко, правда, чисто административного плана или саппортится не все низкоуровневые API (урезанный рантайм).

                                                                                      0
                                                                                      Разработчик libstdc++ сейчас продумывает механизм, позволяющий делать нечто подобное.

                                                                                      Возможно что к C++2a будет готово.
                                                                                        0

                                                                                        Спасибо за наводку, послежу.

                                                                                          0
                                                                                          Спсибо!

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

                                                                                  Самое читаемое