constexpr нужны для манипуляциями над данными в RO памяти, которых в программах может быть достаточно много. Например, у нас есть массив, данные в котором мы ищем по индексу. Как не нафакапить при заполнении массива и не промахнуться с индексом? Очень просто, написать constexpr функцию, проверяющую валидность массива и вызвать её из static_assert.
А теперь допустим мы ходим искать в этом массиве не по индексу, а по содержимому.
Сделаем constexpr хэшмапу и будем искать за (примерно) константное время. Впрочем, этот велосипед был скорее на поиграться с возможностями нового с++; в мире розовых поней я лучше подожду constexpr std::unordered_map.
Любителям метапрограммирования с constexpr std::vector откроются новые возможности. Так например подобное нечитаемое безобразие просто не надо будет писать, так как можно будет обойтись std::vector и алгоритмами из стандартной библиотеки. Метапрограмный код получится читаемый, а не тот что мы имеем в C++14/17.
Не является ли данный пример типичным местом применения для gsl::span?
Кстати, как дела у std::array_view, всё заглохло?
constexpr строки и вектора это оч хорошо (вью же не сложишь), но на моей практике многое делается уже c одним gsl::span (хотя я знаю у себя место где constexpr вектор бы упростил код)
Upd: а, там массив возвращается; ну да, вектор полезен был бы
Как такое сделать? Например, какой-то глобальной таблицей/стеком активных блоков try, т.е. при входе в блок try в этот глобальный стек заносится какой-то объект, при выходе — извлекается. При необходимости бросить исключение — проверяется, а нет ли в этом стеке объекта соответствующего типа. При нормальной (успешной) работе функций это вроде бы никаких накладных расходов не создает.
Вообще-то, именно так и реализованы блоки try-catch в с++ =)
Например, если обработчика исключения нет, то throw смотрит в таблицу текущих обработчиков, видит, что там пусто и вызывает terminate не разматывая стек до main().
Комментарий ноунейма.
С одной стороны, мне дико нравится пропозал, он гораздо лучше чем std::expected который имхо имеет нерешенные проблемы в том виде, в котором его предложил саттер (а именно, выброс значения, хранимого в error, при доступе к значению — ведь базовая идея чтобы возвращать вместе с типом что-то не очень тяжелое, скажем, код ошибки; и получается, что мы кидаем энум или там int или строку… в общем, что-то, что не наследует std::exception; с одной стороны, ловить int язык позволяет, с другой — говнокод).
С другой, вспоминается картинка про 14 конкурирующих стандартов.
Ведь проблема не столько в легаси коде; какой-нибудь Гугл или фейсбук с монорепозиторием могут потратить месяц на поправку сигнатуры функции и исправление ошибок компиляции (хотя часто есть задачи понасущнее)…
А вот захочу я модернизировать какой-нибудь int QString::toInt(bool *ok=nullptr) const;
Во что-то типа
std::optional QString::toInt() const;
Понятное дело, у меня не получится-ок, я сделаю свободную функцию (давно пора):
std::optional Qt::toInt(QStringView);
А старую объявлю deprecated. А ещё через 5 лет мне придётся менять сигнатуру на
int Qt::toInt2(QStringView) throws(ParseError);
А пользователям придётся каждый раз исправлять код… так и приходится жить с богомерзким возвратом эррор кода через ссылку/указатель, ведь надо чуть-чуть подождать и можно будет использовать новый true-way
Вот как поменять поведение std::vector::at без введения std2? Я не очень представляю, если честно.
Кстати, Дефект N94 не является дефектом. Индекс действительно может быть отрицательным. И массив, в котором лезут в отрицательный элемент, на самом деле не массив, а наследник вектора, который перегружает operator[] чтобы обрабатывать этот случай.
Отрицательный индекс сигнала означает «все сигналы» что бы это ни значило…
Другой дело, что код запутанный выходит.
Интересно, если посмотреть в тот же qimagescale.cpp, то там гораздо больше примеров V668, но PVS Studio на них не срабатывает. Дело в том, что проверка на nullptr после new происходит на сразу после new, а в коде вызывающем функцию, которая делает new а потом возвращает этот указатель. В общем, фич-реквест в PVS Stuido — научиться анализировать call stack для V668.
кстати коде-стайл нарушен, значения енумов в Qt именуются с БольшойБуквы.
Тут не анализатор нужен, а clang-tidy/clang-formatter который должен бить по рукам тем кто не по код-стайл пишет.
Уроки огонь, спасибо всем переводившим. Изучал OGL в универе, но всё забылось и я решил освежить в памяти. Примеры адаптировал для Qt (разбираться в куче новых библиотек было лень), в какой-то момент стал уроки заливать на гитхаб. Вдруг кому пригодится, кто пойдет тем же путём:)
Спасибо за быстрый ответ!
Я просто поясню, что взрывает мозг — то, что в обоих случаях мы _пишем_ (и читаем) в top. Аргумент про семантику более-менее понятен, но ведь процессор работает не в терминах чтения\записи в стек, а в терминах чтения\записи конкретных адресов (top). И как происходит этот переход, не очень ясно (ведь уровень команд синхронизации процессора весьма далек от семантики конкретного контейнера).
С точки зрения записи в top, парой к release мог бы быть guard.protect( m_Top ), если бы он использовал acquire семантику (но это, вероятно, не так, и он использует relaxed).
Верно я понимаю, что рассматривая семантику мы как бы говорим, что если происходит push/pop, то менять их местами нельзя (ведь стек может быть пуст), а pop/push — пожалуйста (ну вытолкнем мы 2й элемент, а не 1й, ну бывает).
Нет, вы не правы. Во-первых, врядли кто-либо разрешит засунуть ICU в стандартную библиотеку (как зависимость, а-ля pthreads). То есть можно сразу забыть о std::to_lower(«АБВ») и друзьях (привет, QString::number, QString::localeAwareCompare) — скажут дергайте ICU руками. Но это не оч удобно.
Во-вторых, никто не торопится в стандарт добавить функции работы непосредственно со строками — нормальный replace, split/join. Да, возможно, в виде генерик алгоритмов они смотрелись бы лучше, но… Пока никто не написал proposal на это, а значит приходиться кушать что дают. Сюда же попадает localeAwareCompare, он сейчас юзает платформенные функции для (т.е. ICU не особо нужен), но о5 же, нет пропозала в стд для аналога.
В третьих, кодеки для разных кодировок — std::u16string тупо массив short'ов без знания о том, Big-Endian, Little-Endian он или ещё какой.
Вот было огромное обсуждение касательно QString/QStringView (utf16 vs utf8 там тоже затронули).
В общем, сейчас политика партии такова — обоже никогда не юзайте QList, вместо QVector используйте std::vector, вместо QScopedPointer — std::unique_ptr, если это не касается публичного API. До сих пор нет решения касательно холивара «юзать ли std:: в публичном API». Из-за обещаний BC между версиями, нельзя юзать стандартные типы (вдруг stdlib поменяет BC), но слом BC в стандартной библиотеке всё равно ведёт к пересборке всего мира, так что, надеюсь, этот холивар разрешится в пользу std:: к 6й версии). Например, зарезали мою реализацию QOptional (aka std::experimental::optional) — юзай std, говорят. Аналогично не хотят добавлять move-семантику в QScopedPointer (зачем, если есть unique). А вот QString/QStringView/QByteArray — скорее исключения из правила юзать std.
А так, QThread уже давно внутри юзает std::thread (только наворачивает эвентлуп поверх), атомики юзают std:: и только QString живёт и процветает потому что аналога в стандартной библиотеке всё ещё нет.
Qt может быть скомпилена с поддержкой ICU (вкл по дефолту), тогда какие-то вещи QString/QLocale и друзья делают через ICU. Какие конкретно — сказать не могу, не копал так глубоко.
В общем случае, Qt не переизобретает велосипед, а умеет только какие-то базовыве вещи, т.е. ICU шире. Ну а фигли, там либа весит больше чем QtCore)
А оно по-прежнему реализовано на QML? Перефразирую — когда я смотрел, там был с++ класс, к-ый отвечает за рисование стилем, а все элементы были написаны поверх него на QML. Кажется, что реализовать полный функционал виджетов на одном QML достаточно сложно. К примеру — их новый комбобокс поддерживает редактирование и возможность подменить попап виджет на свою вьюху? Что с комплитером/валидатором? Что с кнопками — в них можно втыкать меню? Когда я смотрел, этого не было. Что-нибудь изменилось?
Кажется, что использование паттерна Команда как простого коллбэка — это один из наиболее редких юзкейзов.
Основные, как мне кажется — объединить код и данные с целью манипуляции этими данными — например сохранить команды, чтобы иметь возможность повторно применить их к другому объекту; или иметь возможность откатить изменения (для этого в команде должен быть метод undo). Или сбросить команды на диск как «историю» изменений.
Более хитрый юзкейз — слияние однотипных подряд идущих команд в одно действие — тоже может быть полезен.
Я где-то читал, что настоящее время лучше писать для того, чтобы было удобнее читать что делаеют коммиты при интерактивном ребейзе — ведь мы только собираемся пикнуть тот или иной коммит, а там прошедшее время.
То есть Cairo в стандарте не смущает (а это и есть пропозал), а libpng смущает?)
А теперь допустим мы ходим искать в этом массиве не по индексу, а по содержимому.
Сделаем constexpr хэшмапу и будем искать за (примерно) константное время. Впрочем, этот велосипед был скорее на поиграться с возможностями нового с++; в мире розовых поней я лучше подожду constexpr std::unordered_map.
Не является ли данный пример типичным местом применения для gsl::span?
Кстати, как дела у std::array_view, всё заглохло?
constexpr строки и вектора это оч хорошо (вью же не сложишь), но на моей практике многое делается уже c одним gsl::span (хотя я знаю у себя место где constexpr вектор бы упростил код)
Upd: а, там массив возвращается; ну да, вектор полезен был бы
Вообще-то, именно так и реализованы блоки try-catch в с++ =)
Например, если обработчика исключения нет, то throw смотрит в таблицу текущих обработчиков, видит, что там пусто и вызывает terminate не разматывая стек до main().
Комментарий ноунейма.
С одной стороны, мне дико нравится пропозал, он гораздо лучше чем std::expected который имхо имеет нерешенные проблемы в том виде, в котором его предложил саттер (а именно, выброс значения, хранимого в error, при доступе к значению — ведь базовая идея чтобы возвращать вместе с типом что-то не очень тяжелое, скажем, код ошибки; и получается, что мы кидаем энум или там int или строку… в общем, что-то, что не наследует std::exception; с одной стороны, ловить int язык позволяет, с другой — говнокод).
С другой, вспоминается картинка про 14 конкурирующих стандартов.
Ведь проблема не столько в легаси коде; какой-нибудь Гугл или фейсбук с монорепозиторием могут потратить месяц на поправку сигнатуры функции и исправление ошибок компиляции (хотя часто есть задачи понасущнее)…
А вот захочу я модернизировать какой-нибудь int QString::toInt(bool *ok=nullptr) const;
Во что-то типа
std::optional QString::toInt() const;
Понятное дело, у меня не получится-ок, я сделаю свободную функцию (давно пора):
std::optional Qt::toInt(QStringView);
А старую объявлю deprecated. А ещё через 5 лет мне придётся менять сигнатуру на
int Qt::toInt2(QStringView) throws(ParseError);
А пользователям придётся каждый раз исправлять код… так и приходится жить с богомерзким возвратом эррор кода через ссылку/указатель, ведь надо чуть-чуть подождать и можно будет использовать новый true-way
Вот как поменять поведение std::vector::at без введения std2? Я не очень представляю, если честно.
Отрицательный индекс сигнала означает «все сигналы» что бы это ни значило…
Другой дело, что код запутанный выходит.
Тут не анализатор нужен, а clang-tidy/clang-formatter который должен бить по рукам тем кто не по код-стайл пишет.
Иначе будет неприятное моргание вместо плавного перехода.
Я просто поясню, что взрывает мозг — то, что в обоих случаях мы _пишем_ (и читаем) в top. Аргумент про семантику более-менее понятен, но ведь процессор работает не в терминах чтения\записи в стек, а в терминах чтения\записи конкретных адресов (top). И как происходит этот переход, не очень ясно (ведь уровень команд синхронизации процессора весьма далек от семантики конкретного контейнера).
С точки зрения записи в top, парой к release мог бы быть guard.protect( m_Top ), если бы он использовал acquire семантику (но это, вероятно, не так, и он использует relaxed).
Верно я понимаю, что рассматривая семантику мы как бы говорим, что если происходит push/pop, то менять их местами нельзя (ведь стек может быть пуст), а pop/push — пожалуйста (ну вытолкнем мы 2й элемент, а не 1й, ну бывает).
Во-вторых, никто не торопится в стандарт добавить функции работы непосредственно со строками — нормальный replace, split/join. Да, возможно, в виде генерик алгоритмов они смотрелись бы лучше, но… Пока никто не написал proposal на это, а значит приходиться кушать что дают. Сюда же попадает localeAwareCompare, он сейчас юзает платформенные функции для (т.е. ICU не особо нужен), но о5 же, нет пропозала в стд для аналога.
В третьих, кодеки для разных кодировок — std::u16string тупо массив short'ов без знания о том, Big-Endian, Little-Endian он или ещё какой.
Вот было огромное обсуждение касательно QString/QStringView (utf16 vs utf8 там тоже затронули).
В общем, сейчас политика партии такова — обоже никогда не юзайте QList, вместо QVector используйте std::vector, вместо QScopedPointer — std::unique_ptr, если это не касается публичного API. До сих пор нет решения касательно холивара «юзать ли std:: в публичном API». Из-за обещаний BC между версиями, нельзя юзать стандартные типы (вдруг stdlib поменяет BC), но слом BC в стандартной библиотеке всё равно ведёт к пересборке всего мира, так что, надеюсь, этот холивар разрешится в пользу std:: к 6й версии). Например, зарезали мою реализацию QOptional (aka std::experimental::optional) — юзай std, говорят. Аналогично не хотят добавлять move-семантику в QScopedPointer (зачем, если есть unique). А вот QString/QStringView/QByteArray — скорее исключения из правила юзать std.
А так, QThread уже давно внутри юзает std::thread (только наворачивает эвентлуп поверх), атомики юзают std:: и только QString живёт и процветает потому что аналога в стандартной библиотеке всё ещё нет.
В общем случае, Qt не переизобретает велосипед, а умеет только какие-то базовыве вещи, т.е. ICU шире. Ну а фигли, там либа весит больше чем QtCore)
Вообще-то умеет
Другое дело, что Unicode итераторы нифига не документированы, но вот, скажем, пример
Основные, как мне кажется — объединить код и данные с целью манипуляции этими данными — например сохранить команды, чтобы иметь возможность повторно применить их к другому объекту; или иметь возможность откатить изменения (для этого в команде должен быть метод undo). Или сбросить команды на диск как «историю» изменений.
Более хитрый юзкейз — слияние однотипных подряд идущих команд в одно действие — тоже может быть полезен.