Комментарии 90
Вторая проблема — это скорость компиляции. Конечно, хорошо сиделать на Cling и получать REPL от Clang (даже если вы под Windows), но все же хочется и компилировать во вменяемые сроки. А модули могли уже сделать ой как давно, но че-то до сих пор тянут резину.
В третьих, хочется чтобы закончились «пакетные войны» и С++ пришли к стандарту о пакет-менеджменте, даже если этот стандарт подразумевает локальную компиляцию. Rust эту проблему как-то решил, может решить и С++ если не пытаться делать из этого коммерческий продукт (привет, biicode) а просто зарелизить и хорошо пропиарить что-то работающее.
Но если уж вам действительно хочется порыться в языке в попытке сделать его лучше, то я бы предложил несколько простых вещей:
- Extension methods, т.к. они проверены временем и реально нужны
- Properties, т.к. они проверены временем и реально нужны
- Дефолтные шортхэнды для лямбд, т.к. [](){} в большинстве случаев не надо. Также дефолтные параметры для аргументов лямбд ($0, $1, итд, привет Rust), возможность не писать [] (делая автоматов [=] для литералов вроде int32_t и [&] для всего остального, как собственно в C#), возможность не писать () если аргументов нет.
Вот пока все выше не сделано, обсуждать новые операторы и прочие извраты имхо рановато. Нужно сначала привести язык к состоянию, когда студент может на него посмотреть и его не будет тошнить от неудобоваримости увиденного. И вот тогда можно ваять новые фичи.
Да и насчет spaceship operator — если надо чтобы простой класс определял весь пакет операторов и сразу, посмотрите на Котлиновский data class, это как раз то что нужно.
Ну и STL нужно выводить на «бытовой» уровень — добавить например поддержку разных форматов (XML или PNG, например) из коробки, чтобы не надо было на каждый чих копать чужие сорцы, написанные во времена С.
Поддерживаю целиком и полностью! Вам интересно будет начать писать proposal+прототип и прорабатывать эту идею в stdcpp.ru?
Extension methods, т.к. они проверены временем и реально нужны
Можете предложить синтаксис (здесь или на stdcpp.ru)?
Дефолтные шортхэнды для лямбд, т.к. [](){} в большинстве случаев не надо. Также дефолтные параметры для аргументов лямбд ($0, $1, итд, привет Rust), возможность не писать [] (делая автоматов [=] для литералов вроде int32_t и [&] для всего остального, как собственно в C#), возможность не писать () если аргументов нет.
() можно уже давно не писать.
«автоматом [=] для литералов вроде int32_t и [&] для всего остального» — ночной кошмар при отладке, суровая возможность убить себе производительность. Лично я очень не люблю [=] и [&], пожалуйста не надо делать их использование ещё проще.
Vector3, Matrix4x4 — над подобными типами данных работают, но я не в курсе прогресса по ним. В C++17 их точно не будет.
необходимость всегда первым делом тащить в проект libpng, libjpg, libzip и прочее что уже стало неким стандартом… это даже более важное чем модули
А почему нельзя ввести модули и оформить вышеописанные библиотеки как модули, которые было бы легко подключать?
Часть этих проблем, кстати, отсутствует, если писать под Windows (да, готов принимать помидоры за это утверждение). Изображения открываются через GDI+ абсолютно простыми и понятными методами. В WinAPI присутствуют функции для работы со строками с преобразованием CP??? <-> UTF-8 <-> UTF-16, есть CompressionAPI для работы с zip.
Отличие же libpng, libjpg и т.д. заключается в том, что они являются самостоятельными библиотеками, а не частью API операционной системы. Хорошо это или плохо — ответ неоднозначаный: хорошо, потому что отвязываемся от реализации в конкретной ОС, плохо — тащим с собой кучу кода, имеем проблемы с его подключением.
В WinAPI присутствуют функции для работы со строками с преобразованием CP??? <-> UTF-8 <-> UTF-16
нормальный API для работы со строками должен как минимум принимать на себя задачи по управлению памятью.
В принципе особенных проблем с конвертацией сейчас нет, особенно из юникода в юникод.
#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 строками будет чуть сложнее, но задача тоже решаемая.
А какую библиотеку лучше взять libjpeg, libjpeg-turbo или mozjpeg? Если запихнуть Qt в stdlib, то как часто мы будем получать новую версию? За 4 года Qt поменял версию с 5.0 до 5.7.
отсутвие возможности в std сделать конвертацию cp1251 -> utf8 и обратно
В принципе при использовании std::locale и в целом Localization library уже сейчас можно спокойно написать конвертор для более простого конвертирования из ANSI локали в нужный UNICODE и обратно и внести его в стандарт, проблемы то нет особо. Там не особо большие изменения требуются.
Сахар в духе Properties, конечно, неплох, но не так уж он и нужен. Никто не запрещает вам иметь get/set методы. Extension методы вообще относительно спорная штука.
Есть куча других нужных вещей, которых еще нет, я не спорю. Но добавление нового способа делать то, что и так уже нормально работает из коробки — это ИМХО, не должно быть приоритетом.
Сахар в духе 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; }
У многих это вызывает БООООЛЬ ;)
...
#define CONST const
...
#define CONST __flash
...
Такой вот он IoT :)
Ну и STL нужно выводить на «бытовой» уровень — добавить например поддержку разных форматов (XML или PNG, например) из коробки, чтобы не надо было на каждый чих копать чужие сорцы, написанные во времена С.
Мало библиотек сорцами времен C++11?
P.S. искать мне не лень и самому, но я уже давно не могу найти работающую замену старым решениям, к сожалению.
привет, biicode
Есть такой проект, от создателей biocide: conan.io. Вроде интересен сам по себе: не зависит от системы сборки, неитрузивный, можно поднимать локальный репозиторий. Но репозиторий почти пуст, коммитят в них полтора человека, да и те — авторы проекта. Непонятно, будет он жить, или нет (вроде, обещают интеграцию с Artifactory), но с технической точки зрения — штука интересная.
Нужно чтобы conan.io научился работать с NuGet, а NuGet с conan.io. Тогда, наверное, проблемы со стандартизацией будут решаемые.
Да, vcpkg выглядит хорошо — как apt-get для Windows.
Вот сравнение с NuGet и Conan.io
Ну на первый взгляд он выглядит так, будто его не проблема и на линуксе завести, хотя использовать для описания пакетов cmake немного странно выглядит, но с другой стороны это должно как-то легко приделываться к любому другому cmake проекту.
>> Extension methods
Поиспользовал в C#, уже нет особого желания их использовать, особенно когда в них начинают пихать нереальных размеров всякий бред, сложную логику и работу с БД. С одной стороны полезно, в комбинации с адекватными лямбдами можно сделать без боли в одном месте аналог linq (C#) и streams (Java), но по ощущениям не самая важная вещь. Уж лучше asio перетащить в stl, пользы будет больше, да хотя бы boost::di докинуть.
>> Properties, т.к. они проверены временем и реально нужны
Я бы сказал, хорошо там где нас нет. Пожив в C#, почитав Рихтера, пришло понимание, что может быть данная концепция и удобна, но постоянные злоупотребления приводят к очень неприятным последствиям. Меняете свойство, ожидаете одно поведение, а ловите непонятно что. То дедлок, то эксепшен, то меняются другие свойства, то еще куча всего. В итоге я бы не стал трогать, кому надо, тот сделает себе эти самые свойства существующими средствами языка.
Лямбды, надо смотреть в сторону других языков, я не понимаю, зачем надо описывать захваты, если в большинстве случаев можно определить из контекста. $0, $1 вот не надо такого счастья, не могу ничего доброго вспомнить о Perl с его невообразимой куче всяческих переменных такого вида. Разбираться в таком коде и врагу не пожелаешь.
Лямбды, надо смотреть в сторону других языков, я не понимаю, зачем надо описывать захваты, если в большинстве случаев можно определить из контекста.
Мне кажется что в большом количестве случаев, определить из контекста невозможно:
int a = 0;
int b = some_value();
auto f = [?a, b]() mutable {
++b;
a += b;
std::cout << a;
};
if (something()) {
++a;
}
f();
Хотел тут пользователь передать «a» по ссылке или по копии? Формализовать логику копия/ссылка будет очень тяжело, она может значительно замедлить компилятор и приводить к не очевидному поведению.
Поиспользовал в C#, уже нет особого желания их использовать
Я их использую как альтернативу плюсовому функционалу по специализации шаблонов.
И очень не хватает перегрузки операторов в C# для дженериков: почему extension-методы допустимы, а перегрузки операторов (суть то же самое) — нет?
Extension methods конечно хорошо, но затруднит читаемость кода.
Ну а с лямбдами всё спорно, изначально у них странный синтаксис. Меня всегда особенно беспокоил возвращаемый тип через '->', это уж совсем как-то мерзковато.
STL уже давно никуда не годиться, и работать с ним не удобно и выглядит всё порой страшновато, да и много нужных вещей не хватает. Но с другой стороны новый STL2 тоже ни к чему, к хорошему это не приведет, т.к. все сразу захотят свой STL.
и его не будет тошнить от неудобоваримости увиденного
Ну это очень спорно. Когда уже долго пишешь на плюсах его синтаксис начинает казаться идеалом.
Ну а с лямбдами всё спорно, изначально у них странный синтаксис.
у них лаконичный синтаксис
Меня всегда особенно беспокоил возвращаемый тип через '->', это уж совсем как-то мерзковато.
а в чем проблема? Во многих яп используется такой синтаксис. Особенно с учетом того, что в большинстве случаев указывать тип возвращаемого значения не нужно.
Ну это очень спорно. Когда уже долго пишешь на плюсах его синтаксис начинает казаться идеалом.
едва ли идеалом, но полный контроль над происходящим — то, к чему привыкаешь и чего в большинстве языков нет и никогда не будет.
- Дефолтные шортхэнды для лямбд, т.к. [](){} в большинстве случаев не надо. Также дефолтные параметры для аргументов лямбд ($0, $1, итд, привет Rust), возможность не писать [] (делая автоматов [=] для литералов вроде int32_t и [&] для всего остального, как собственно в C#), возможность не писать () если аргументов нет.
Вот пока все выше не сделано, обсуждать новые операторы и прочие извраты имхо рановато. Нужно сначала привести язык к состоянию, когда студент может на него посмотреть и его не будет тошнить от неудобоваримости увиденного.
Мне кажется что при наличии таких брёвен (возможно объективно неизбежных) как нотация шаблонов, смысл которых в конечном итоге получается как раз в попытке привнести техники функционального программирования в C++ говорить об улучшении синтаксиса лямбд по большому счету похоже на вычищение соринок.
Но это так к слову. Главное что, вот всё-таки это всё больше похоже на предложения по введению синтаксического сахара (причем достаточно субъективного с т.з. пользы), чем на улучшения в языке. И ставить в зависимость от него введение новых фич мне кажется неправильно.
Если говорить и приглашать к предложению новых идей для C++, то при организации всего этого стоит четко представлять себе ценность, мотивацию и место, которое занимает то или иное предложение с инженерной точки зрения — это либо исправление логической несогласованности и снятие искусственных ограничений как примеры в статье, либо действительно полезная для разработки фича, уточнение базовых идей, которое делает язык идейно простым и понятным (в качестве самого показательного примера можно привести новые правила генерации специальных функций-членов класса), либо же это очередная претензия студента к тому, как надо записывать лямбды, чтобы они смотрелись красиво (или по привнесению каких-то ещё как они любят выражаться "вкусных плюшек" из других знакомых языков: C#, Pyton, Rust чтоб было так же "удобно" и "круто"), либо какой-нибудь синтакическо-семантический хак для реализации некой красивой идеи, либо ещё что-то. В общем каждый, кто имеет опыт участия в обсуждении предложений по "улучшению" какого-либо языка программирования наверняка может представить во что всё это может выливаться. :)
1. Независимая трансляция каждого cpp-файла сильно замедляет процесс компиляции, особенно если используется большое количество инклюдов и шаблонного кода. Компиляция должна быть на уровне проекта, а не файла.
2. Сложность с подключением библиотек: статические библиотеки не являются самодостаточными, их нельзя просто взять и подключить, как в других языках. Изволь тянуть с собой кучу инклюдов и не забывать прописывать пути.
Но я сомневаюсь, что здесь будут подвижки. Переход на модули, например, поломает частичную специализацию шаблонов и кол, использующий директивы препроцессора. Это потребует переписывания всей стандартной библиотеки. Получится, фактически, не надстройка над C++, а новый язык.
Когда вы собираете проект, каждый cpp файл может компилироваться параллельно (это хорошо, отличная масштабируемость).
Однако, как правило, вы используете одни и те же заголовочные фалы в каждом cpp файле. За счет того, что компиляция различных cpp фалов никак не связана друг с другом, при каждой компиляции компилятор разбирает одни и те же заголовочные файлы… снова… и снова… Именно этот разбор и тормозит (заголовочный файл iostream весит более мегабайта, подключите 20 подобных заголовочных файлов — и компилятору придётся просмотреть и разобрать около 30 мегабайт кода при компиляции одного cpp файла).
Модуль — это набор файлов, собранных воедино и сохранённых на диск в понятном для компилятора бинарном виде. Таким образом, при подключении модуля, компилятор просто считает его с диска в свои внутренние структуры данных (минуя этапы открытия нескольких фалов, парсинга, препроцессинга и некоторых других вспомогательных вещей).
Дополнительный прирост скорости при компиляции будет получен за счёт того, что в модуле вы явно указываете его публичный интерфейс. То есть компилятор сможет сделать ряд оптимизаций ещё при создании модуля. Это сильно уменьшит затраты оперативной памяти, ускорит поиск подходящих перегруженных функций, структур и т.п за счёт того, что их будет просто меньше.
И наконец, финальная стадия сборки проекта — линковка. В данный момент линковщик много времени тратит на выкидывание одинаковых блоков скомпилированного кода (вы подключили iostream 100 раз — линкер выкинет 99 скомпилированных std::cout). С модулями есть шанс, что линкеру не придется этим заниматься, т.к. файл модуля не будет вкомпиливаться внутрь собранного cpp файла.
Модули ничего не ломают, иначе бы их не принимали в стандарт. Модули не будут автоматически генерироваться для вашего проекта. Вам придется постараться и описать публичные интерфейсы модуля, чтобы получить дополнительные плюшки модулей.
Еще можно добавить про precompiled headers на «используется большое количество инклюдов и шаблонного кода».
С помощью g++ можно, например, компилировать программу как единое целое, минуя создание объектников.
С помощью g++ можно, например, компилировать программу как единое целое, минуя создание объектников.
Если вызвать «g++ -flto file1.cpp file2.cpp», то объектники всё-равно создадутся (в /tmp), потом подадутся линкеру, и он опять позовёт gcc для перекомпилиции с межпроцедурными оптимизациями. Можно подать опцию -v и увидеть все подробности.
Да, именно этим и занимались линковщики в 80-90-е годы
И продолжают заниматься по сей день. Было бы неплохо, чтобы эта часть сборки происходила ещё быстрее :)
А мне вот отвратительно видеть, что в этом пропозале форсируется использование паттерна проактор (по сути весь Asio, как есть), тогда как на том же Linux/FreeBSD да и вообще всех Unix — реактор реализуется меньшими накладным расходами.
Т.е. моё мнение, что код для сокетов должен быть оторван от асинхронности. Абстракция над сокетами — отдельно. Асинхронная работа — отдельно. И вот тут бы было неплохо иметь возможность выбора стратегии.
Сама абстракция над сокетами же, работа с параметрами сокетов — мне нравится. Даже можно выпендриться и использовать только её, скрестив, допустим, с libev: когда игрался получился заметный выигрыш в попугаях на стендовом http сервере.
Ну а что касается сокетов: не хочется жертвовать производительностью ради универсальности. В драфтах, например, не планируется использование ни epoll, ни IO completion ports.
В драфтах, например, не планируется использование ни epoll, ни IO completion ports.
Мы точно про одни и те же драфты говорим?
Мы точно про одни и те же драфты говорим?
Не знаю. Я вот этот драфт имел в виду:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4612.pdf
Драфт Networking основан на ASIO, активно разрабатывался тем же разработчиком и ASIO является прототипом к TS. Можете посмотреть на реализацию ASIO, и там вы найдёте использование epool, pool, select, iocp (в зависимости от платформы).
не планируется использование ни epoll, ни IO completion ports.
я или что-то не то смотрел, но нетворкинг это практически Asio как есть. epoll/IOCP это детали реализации. Ну а то, что оверхеда с epoll больше за счёт эмуляции проактора на реакторе — это архитектурный прогиб под IOCP.
из-за ваших стандартов пришлось перейти на C# как на более стабильный стандарт C++ :p
Спасибо!
Планов по тому чтобы пометить allocator::construct как deprecated нет. Люди не очень любят аллокаторы, но согласны что эти функции должны его принимать. Так что стоит написать proposal на добавление перегрузок принимающих Allocator.
Опишите вашу идею на https://stdcpp.ru/proposals чтобы она не потерялась и чтобы можно было собрать отзывы. Как будете готовы — всячески помогу с написанием proposal.
Лучше бы вместо костылей в виде оператора <=> запилили аналог derive из раста, решило бы ВСН проблемы с автоматической генерацией операторов.
Да хотя бы очевидностью процесса: если нам нужен конструктор копирования или операторы сравнения, то мы пишем #[derive(Clone, ParialEq)] и они только в этом случае генерируются. Эту идею можно совместить с концептами и все операторы выразить через них, а также много чего еще, к примеру обозначить уровень потокобезопасности класса или сгенерировать для него автоматически методы для сериализации/десериализации его полей.
Давайте уж лучше сделаем
Какой православный метод предполагается в данном случае?
Остальные итераторы никто не трогал, ими всё ещё можно (и нужно) пользоваться.
А вот поддержка 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 создается на стеке?
— в целом хранение счетчика ссылок «далеко» от самого объекта существенно снижает производительность.
Я бы предложил создавать счетчик прямо в объекте (так быстрее и не нужны костыли), и запретить создавать такие объекты на стеке, еще на этапе компиляции!
Хотелось бы, что-бы 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 решает эту проблему. Везде и всегда его используйте!
Дайте аналог 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. Ну и ограничить применимость только для массивов, так как я слабо представляю необходимость такой процедуры для единичного элемента в памяти.
Да, я согласен. Но иногда в тесных рамках embedded бывают ограничения на использование STL. Собственно там как раз такое и сильно треба бывает.
Контроллеры бывают разные: между AVR8 и PIC и Rapberry PI пространства очень много и оно далеко не пустое. Так что и аллокации в куче бывают нужны/позволительны. А вот ограничения на использование STL бывают, нередко, правда, чисто административного плана или саппортится не все низкоуровневые API (урезанный рантайм).
Возможно что к C++2a будет готово.
С++17 и С++2a: новости со встречи ISO в Иссакуа