В начале ноября в американском городе Иссакуа завершилась встреча международной рабочей группы 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++, узнать что о ней думают другие и обсуждать предлагаемые идеи другими разработчиками. Добро пожаловать!
Поделиться с друзьями
-->

Комментарии (87)


  1. mezastel
    01.12.2016 18:59
    +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, это как раз то что нужно.


    1. antoshkka
      01.12.2016 19:14
      +6

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

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

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

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

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

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

      «автоматом [=] для литералов вроде int32_t и [&] для всего остального» — ночной кошмар при отладке, суровая возможность убить себе производительность. Лично я очень не люблю [=] и [&], пожалуйста не надо делать их использование ещё проще.


      1. Rezzet
        02.12.2016 15:58
        +3

        Одна из самых больших болей в с++ c которой сталкивался, это использование в каждой более-менее большой библиотеке своих строк, своих типов для Vector3, Matrix4x4, отсутвие возможности в std сделать конвертацию cp1251 -> utf8 и обратно, необходимость всегда первым делом тащить в проект libpng, libjpg, libzip и прочее что уже стало неким стандартом, по хорошему я бы пол Qt в stdlib запихнул, особенно по части работы с форматами мультимедия. это даже более важное чем модули, которые кстати то же нужны, на с++ сейчас смешно без этого смотреть.


        1. antoshkka
          02.12.2016 16:13

          У меня нет большого опыта конвертации кодировок, работы с libpng и libjpg. Если у вас есть идеи о том, как правильно их внедрить в стандарт — пишите обязательно, постараюсь по максимуму вам помочь.

          Vector3, Matrix4x4 — над подобными типами данных работают, но я не в курсе прогресса по ним. В C++17 их точно не будет.


        1. DistortNeo
          02.12.2016 23:38

          необходимость всегда первым делом тащить в проект libpng, libjpg, libzip и прочее что уже стало неким стандартом… это даже более важное чем модули


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

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

          Отличие же libpng, libjpg и т.д. заключается в том, что они являются самостоятельными библиотеками, а не частью API операционной системы. Хорошо это или плохо — ответ неоднозначаный: хорошо, потому что отвязываемся от реализации в конкретной ОС, плохо — тащим с собой кучу кода, имеем проблемы с его подключением.


          1. Antervis
            03.12.2016 12:30

            В WinAPI присутствуют функции для работы со строками с преобразованием CP??? <-> UTF-8 <-> UTF-16

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


            1. IRainman
              03.12.2016 14:23
              +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 строками будет чуть сложнее, но задача тоже решаемая.


        1. RPG18
          03.12.2016 00:00

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


          1. Antervis
            03.12.2016 12:18

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


            1. RPG18
              03.12.2016 13:54

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


        1. IRainman
          03.12.2016 14:20

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

          В принципе при использовании std::locale и в целом Localization library уже сейчас можно спокойно написать конвертор для более простого конвертирования из ANSI локали в нужный UNICODE и обратно и внести его в стандарт, проблемы то нет особо. Там не особо большие изменения требуются.


      1. mezastel
        03.12.2016 01:33

        Я написал большое полотно но кнопка «Опубликовать» на сайте делает ровно ничего :(


        1. antoshkka
          03.12.2016 21:28

          Пожалуйста, напишите в личку, каким браузером пользуетесь, ОС и вышлите пожалуйста принтскрин.


    1. 0xd34df00d
      01.12.2016 19:17
      +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).


    1. daiver19
      01.12.2016 19:23
      +7

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

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

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


      1. IRainman
        03.12.2016 14:29

        Сахар в духе 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; }
        


        У многих это вызывает БООООЛЬ ;)


      1. IRainman
        03.12.2016 14:48

        P.S. «CONST» это не опечатка это тоже вынужденная мера поскольку код используется сразу на нескольких сильно разных платформах, одна из которых вообще микроконтроллер и там очень тяжко с ресурсами и местами сильно плохо в целом, typedef не спасает ибо не везде работает и в итоге там вот такое безобразие:

        ...
        
        #define CONST const
        ...
        
        #define CONST __flash
        
        ...
        


        Такой вот он IoT :)


    1. RPG18
      01.12.2016 19:56

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

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


      1. eiskalt
        01.12.2016 23:14
        +2

        Есть ли пример «проверенного» SAX XML парсера на C++11?


      1. IRainman
        04.12.2016 21:48

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

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


    1. GamePad64
      01.12.2016 20:16

      привет, biicode

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


      1. antoshkka
        01.12.2016 20:36
        +1

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

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


        1. stepik777
          01.12.2016 22:01
          +1

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


          1. KindDragon
            02.12.2016 22:56

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


            1. Gorthauer87
              03.12.2016 18:48

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


              1. GamePad64
                05.12.2016 09:52

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


                1. Gorthauer87
                  05.12.2016 12:07

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


    1. AxisPod
      01.12.2016 20:41

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

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

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

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


      1. antoshkka
        01.12.2016 20:56
        +3

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

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

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


      1. DistortNeo
        01.12.2016 21:03

        Поиспользовал в C#, уже нет особого желания их использовать

        Я их использую как альтернативу плюсовому функционалу по специализации шаблонов.
        И очень не хватает перегрузки операторов в C# для дженериков: почему extension-методы допустимы, а перегрузки операторов (суть то же самое) — нет?


    1. hacenator
      02.12.2016 00:04
      +2

      По моему Properties уже давно успешно реализуются через темплейты.
      Extension methods конечно хорошо, но затруднит читаемость кода.
      Ну а с лямбдами всё спорно, изначально у них странный синтаксис. Меня всегда особенно беспокоил возвращаемый тип через '->', это уж совсем как-то мерзковато.

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

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

      Ну это очень спорно. Когда уже долго пишешь на плюсах его синтаксис начинает казаться идеалом.


      1. DistortNeo
        02.12.2016 00:14
        -3

        По-моему, нужен просто новый удобный диалект C++, который был бы семантически идентичным C++, но синтаксически несовместимым с ним. Все проблемы растут от того, что C++ прирастал костылями, вместо того, чтобы перерасти в новый язык.


        1. hacenator
          02.12.2016 00:15

          Так может тогда проще писать на C#?


          1. DistortNeo
            02.12.2016 00:26

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


      1. Antervis
        02.12.2016 06:39
        +3

        Ну а с лямбдами всё спорно, изначально у них странный синтаксис.

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

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

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


  1. stepanp
    01.12.2016 19:42
    +1

    нет модулей — не нужно


    1. aTwice
      01.12.2016 20:22

      поясните, пожалуйста


      1. AxisPod
        01.12.2016 20:43

        Избавиться от отстрелов всех частей тела с раздельными .cpp и .h файлами.


        1. antoshkka
          01.12.2016 20:45

          Не хочу вас расстраивать, но модули это не лечат.


          1. AxisPod
            01.12.2016 20:50

            Я и не сказал, что файлы сольются в кучу, это привело бы к тому, что компилироваться стало бы всё куда медленее. По крайней мере отстрела конечностей будет меньше.


      1. DistortNeo
        01.12.2016 20:59
        -1

        Нужно избавиться, наконец, от рудимента с разделением на h и cpp:

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

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

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


        1. antoshkka
          01.12.2016 23:51
          +13

          Давайте я вкратце и упрощённо распишу, как работают модули и что именно «тормозит при компиляции»:

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

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

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

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

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

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


          1. hacenator
            02.12.2016 00:08

            Ух ты! Какой большой ответ для человека который не понимает как устроен c++.
            Еще можно добавить про precompiled headers на «используется большое количество инклюдов и шаблонного кода».


          1. DistortNeo
            02.12.2016 00:23

            Да, именно этим и занимались линковщики в 80-90-е годы, бездумно собирая программу из предоставленных объектных модулей. Сейчас же линковщик делает то же самое, что и компилятор — оптимизирует код: основное время линковщика тратится не столько на выбрасывание дублирующегося кода, сколько на межпроцедурную оптимизацию для программы целиком.

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


            1. Gumanoid
              02.12.2016 01:03
              +4

              Межпроцедурную оптимизацию делает не линкер, а компилятор, который вызывается из линкера.

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

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


            1. antoshkka
              02.12.2016 01:03

              Да, именно этим и занимались линковщики в 80-90-е годы

              И продолжают заниматься по сей день. Было бы неплохо, чтобы эта часть сборки происходила ещё быстрее :)


  1. abatyuk
    01.12.2016 20:57

    offtop: Как человек, живущий в Иссакве, прошу — поменяйте спеллинг, пожалуйста


    1. antoshkka
      01.12.2016 21:03

      Два различных поисковика утверждают, что писать надо «Иссакуа» :(


      1. abatyuk
        02.12.2016 17:08

        В англоязычной википедии есть произношение (фонетический алфавит) — оно скорее «Исэква». Ну да ладно =)


    1. micbsv
      08.12.2016 19:46

      Хе-хе я тоже там живу :)
      И да, среди русско-говорящих принято называть «Иссаква»


  1. Daytar
    01.12.2016 22:30
    +3

    Заканчивался 2016 год, а в STL так и нет ВООБЩЕ НИЧЕГО для кроссплатформенной работы с сокетами. И видимо ещё лет 6 не будет… Будем надеяться что хоть filesystem не выкинут туда же.


    1. antoshkka
      01.12.2016 23:13
      +2

      Networking в течение года должен появиться в виде TS (уже отправлен на утверждение его черновик). Сможете воспользоваться кроссплатформенными сокетами ещё до C++2a (возможно что даже до C++17).


      1. monah_tuk
        05.12.2016 07:09

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


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


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


    1. DistortNeo
      02.12.2016 00:09

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

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


      1. Satus
        02.12.2016 00:37

        Ну filesystem уже в TS, если что. В VS как минимум уже можно пользоваться.


      1. antoshkka
        02.12.2016 00:50

        Файловая система в C++17

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

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


        1. DistortNeo
          02.12.2016 01:03

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

          Не знаю. Я вот этот драфт имел в виду:
          http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4612.pdf


          1. antoshkka
            02.12.2016 01:14
            +3

            В нём нет текста, запрещающего использование epoll или IOCP. Платформо специфичные вызовы не описываются в стандарте. Так например вы не найдете CreateThread в описании std::thread.

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


            1. monah_tuk
              05.12.2016 07:12

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


      1. monah_tuk
        05.12.2016 07:11
        +1

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

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


  1. iperov
    01.12.2016 23:12
    -7

    Хватит захламлять язык!
    из-за ваших стандартов пришлось перейти на C# как на более стабильный стандарт C++ :p


    1. domix32
      02.12.2016 00:26
      +3

      А чего ж не на ржавчину сразу?


    1. Satus
      02.12.2016 00:36
      -2

      Если вы смогли просто перейти на другой язык, то С++ вам никогда и не нужен был ;)


  1. Satus
    02.12.2016 00:51
    +2

    Раз уж зашла речь о предложениях, меня всегда интересовало, почему функции std::uninitialized_copy/fill/move не имеют перегрузок, которые принимают аллокатор как дополнительный параметр. Раз уж они внутри всё равно вызывают placement new, почему не сделать перегрузку, которая вместо этого вызывает allocator_traits::construct?


    1. antoshkka
      02.12.2016 09:51

      Похоже на дефект. Поузнаю поподробнее, возможно что к C++2a поправим.

      Спасибо!


  1. Gorthauer87
    02.12.2016 00:56

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


    1. antoshkka
      02.12.2016 01:25

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


      1. Gorthauer87
        02.12.2016 11:20

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


  1. LifeKILLED
    02.12.2016 05:14
    +3

    Ну когда уже в C++ интегрируют Брайнфак, я устал ждать…


    1. antoshkka
      02.12.2016 09:18
      +2

      Надеюсь вы предлагаете Брейнфак, выполнимый на этапе компиляции!

      Давайте уж лучше сделаем Java(слишком скучно), C#(слишком мейнстрим), Erlang (не модно), Node.js (hype спал, оно ещё живо?) Rust на шаблонах. В конце концов, надо успеть отдать должное этому языку, прежде чем он канет в Лету.</troll-mode>


  1. Antervis
    02.12.2016 06:46

    Интересно, когда появится constexpr new (для создания constexpr — объектов, мутабельные версии которых используют кучу)?


    1. antoshkka
      02.12.2016 09:10

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


  1. alexeykuzmin0
    02.12.2016 11:14

    Товарищи, просветите, кто-нибудь: вот раньше при работе с последовательностями данных, по которым мне достаточно проитерироваться, я обычно писал функцию, принимающую пару итераторов: начало и конец (ну еще iterator_tag нужный требовал через enable_if) для того, чтобы можно было передать содержимое любого контейнера (или вообще читать через input_iterator). А сейчас у нас итераторы, я так понял, deprecated, а range еще не введены.
    Какой православный метод предполагается в данном случае?


    1. Satus
      02.12.2016 13:57

      А сейчас у нас итераторы, я так понял, deprecated
      Да нет, с чего бы?


    1. antoshkka
      02.12.2016 14:09
      +2

      Deprecated только вспомогательный класс std::iterator. Этим классом сложно пользоваться (я например не помню, в каком порядке передавать шаблонные параметры) и он бесполезен при написании шаблонных итераторов.

      Остальные итераторы никто не трогал, ими всё ещё можно (и нужно) пользоваться.


      1. alexeykuzmin0
        02.12.2016 16:15
        +1

        Понятно, у меня было неверное понимание. Спасибо


  1. leremin
    02.12.2016 21:00

    Лучше бы стандартизировали декораторы имен (или что там мешает использованию классов в dll) и шаблонов там же. Впрочем, уже 3 года на C# сижу и не жалею.


  1. sunnee
    04.12.2016 15:15

    Всякие 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 создается на стеке?
    — в целом хранение счетчика ссылок «далеко» от самого объекта существенно снижает производительность.

    Я бы предложил создавать счетчик прямо в объекте (так быстрее и не нужны костыли), и запретить создавать такие объекты на стеке, еще на этапе компиляции!


    1. antoshkka
      04.12.2016 15:25

      Хотелось бы, что-бы 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 решает эту проблему. Везде и всегда его используйте!


  1. monah_tuk
    05.12.2016 07:37

    Дайте аналог 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. Ну и ограничить применимость только для массивов, так как я слабо представляю необходимость такой процедуры для единичного элемента в памяти.


    1. Antervis
      05.12.2016 08:42

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


      1. monah_tuk
        05.12.2016 10:10

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


        1. Antervis
          05.12.2016 12:16

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


          1. monah_tuk
            05.12.2016 13:55

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


        1. antoshkka
          05.12.2016 13:02

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

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


          1. monah_tuk
            05.12.2016 13:58

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


          1. g3plc
            07.12.2016 12:46

            Спсибо!