Без лишних слов, прямо к делу — вот какие новые вкусности будут нас ждать в C++23:

  • std::expected — новый механизм сообщения об ошибках без использования исключений и без недостатков кодов возврата.
  • constexpr-математика — теперь на этапе компиляции можно доставать разные части чисел с плавающей запятой, копировать знаки и округлять числа.
  • std::ranges::to — результаты работы алгоритмов можно легко превратить в контейнер.
  • std::views::join_with — добавление разделителя между элементами.

Что мы не увидим в C++23, на что ещё можно надеяться и что ещё приняли в текущий черновик стандарта? Всё это ждёт вас под катом.

std::expected


В C++ для обработки ошибок зачастую используется подход из С — с кодами возврата:

std::errc to_int(std::string_view str, int& result) {
    const auto end = str.data() + str.size();
    auto [ptr, ec] = std::from_chars(str.data(), end, result);
    if (ec == std::errc() && ptr != end) {
        ec = std::errc::invalid_argument;
    }

    return ec;
}

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

int result;
auto err = to_int(data, result); 
if (err != std::errc()) return err;
// ... продолжаем работать с result

При этом в C++ уже долгое время есть механизм обработки ошибок через исключения:

int to_int(std::string_view str) {
    int result;
    const auto end = str.data() + str.size();
    auto [ptr, ec] = std::from_chars(str.data(), end, result);
    if (ec != std::errc() || ptr != end) {
        throw std::runtime_error("failed to parse");
    }

    return result;
}

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

const int result = to_int(data);
// ... продолжаем работать с result

В C++23 добавляется класс std::expected, предназначенный для замены кодов возврата более надёжным и простым в использовании механизмом:

std::expected<int, std::errc> to_int(std::string_view str) {
    int result;
    const auto end = str.data() + str.size();
    auto [ptr, ec] = std::from_chars(str.data(), end, result);
    if (ec != std::errc()) return ec;    
    if (ptr != end) return std::errc::invalid_argument;

    return result;
}

Можно пользоваться результатом как кодом возврата:

auto val = to_int(data);
if (!val) return val;
auto& result = *val;

А если в этом месте ошибки редки, можно вернуться к исключениям:

auto result = to_int(data).value(); // исключение в случае ошибки

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

constexpr


Поддержка вычислений на этапе компиляции в C++ не стоит на месте. В этот раз добавили constexpr unique_ptr в P2273 и constexpr <cmath> в P0533. Делитесь в комментариях идеями, как можно воспользоваться этими возможностями ;-)

std::ranges::join_with


Если вы когда-нибудь программировали на Python после C++, то наверняка испытывали удовольствие от того, как легко можно собрать значения в строку с разделителем:

values = ('Hello', 'world')
print(', '.join(values))  # Выводит Hello, world

Теперь это удовольствие доступно и в C++:

for (const auto& val : {'Hello', 'world'} | std::views::join_with(", "))
    std::cout << val;  // Выводит Hello, world

Всё благодаря замечательному предложению P2441. Наконец-то можно будет заменить boost::algorithm::join стандартным и более эффективным решением.

На подходе, кстати, ещё более удобное решение:

std::map<int, std::string> m{
    {41, "Hello"},
    {42, "world"},
};
auto s = std::format("{:m}", m); // {41: "Hello", 42: "world"}

Надеюсь, что эта идея из P2286 ещё успеет попасть в C++23.

Новые алгоритмы ranges


Добавили ещё больше алгоритмов над диапазонами:

  • std::ranges::iota(range, x) — для переопределения элементов диапазона значениями x++ (P2440).
  • std::ranges::shift_left(range, n) и std::ranges::shift_right(range, n) — для переопределения элементов диапазона значениями из того же диапазона со сдвигом n, по аналогии с std::shift_left/std::shift_right (P2440).
  • std::views::chunk(range, n) — для группировки элементов в диапазоны из n элементов (P2442).
  • std::views::slide(range, n) — группировка по n смежных элементов с шагом 1, аналог std::views::adjacent<n> с рантайм-параметром n (P2442).
  • std::views::chunk_by(range, pred) — разделение на поддиапазоны по предикату pred (P2443).

Примеры использования новых алгоритмов:

std::vector<char> v;
v.resize(4, 'b');                 // v == {'b', 'b', 'b', 'b'}
std::ranges::iota(v, 'm');  // v == {'m', 'n', 'o', 'p'}
std::ranges::shift_left(v, 1);  // v == {'n', 'o', 'p', 'p'}
v | std::views::chunk(2);  // {['n', 'o'], ['p', 'p']}
v | std::views::slide(2);  // {['n', 'o'], ['o', 'p'], ['p', 'p']}
v | std::views::chunk_by([](auto x, auto y) {
    return x != y;
});  // {['n', 'o', 'p'], ['p']}

std::ranges::to


До C++23 сохранить дипазон в контейнер было не самой тривиальной задачей:

auto c = std::views::iota('a', 'z') | std::views::common;
std::vector v(c.begin(), c.end());

Теперь эта задача решается в два раза проще:

auto v = std::views::iota('a', 'z') | std::ranges::to<std::vector>();

Кроме того, в большинство контейнеров стандартной библиотеки добавляются новые методы для работы с диапазонами:

  • c.insert_range(it, r) — для вставки диапазона значений r в контейнер c по итератору it.
  • c.assign_range(r) — для перезаписи значений контейнера c диапазоном значений r.
  • c.append_range(r) — для добавления диапазона значений r в конец контейнера c.
  • c.prepend_range(r) — для добавления диапазона значений r в начало контейнера c.

Благодаря новым функциям работа с std::string упрощается:

std::string s{"world"};
std::string_view hello{"Hello "};

std::cout << s.prepend_range(hello).append_range("!!!"); // Hello world!!!

Помните, что в данный момент std::ranges::to не перемещает элементы, даже если контейнер является временной (rvalue) переменной. Поэтому для написания эффективного кода нужно использовать std::views::move (не путайте с std::move):

namespace views = std::views;
using std::ranges::to;

std::vector<std::u8string> strs{u8"Привет", u8"дорогой читатель"};
auto s0 = strs | to<std::deque>(); // Копирование элементов strs
auto s1 = strs | views::move | to<std::deque>(); // Перемещение элементов strs

so.append_range(s1); // Копирование элементов s1
so.append_range(std::move(s1)); // Всё ещё копирование элементов s1
so.append_range(s1 | views::move); // Перемещение элементов s1

Все детали предложения доступны в документе P1206.

Оператор | для пользовательских ranges


Глядя на все вышеописанные новые views для ranges, невольно задаёшься вопросом: «А как нам самим написать подобный view?» P2387 старается ответить на этот вопрос и вводит для этого дополнительные утилиты:

  • std::ranges::range_adaptor_closure<T> — базовый класс для ваших closure objects, чтобы они могли использовать предоставляемый библиотекой оператор | для комбинирования.
  • std::bind_back(f, args&&...) — вспомогательная утилита для привязывания аргументов функции с конца. Например, вызов std::bind_back(f, a3, a4)(a1, a2) превратится в f(a1, a2, a3, a4).

Но даже с этими утилитами приходится писать как минимум экран кода, чтобы сделать новый view с поддержкой оператора |. Скоро должны подоспеть новые предложения, дополнительно упрощающие написание своих view.

Прочие мелочи


  • В P0627 добавили функцию std::unreachable() для информирования компилятора о недостижимых участках кода (таких, куда программа никогда не заходит во время своего выполнения).
  • В P1413 пометили алиасы наподобие std::aligned_storage_t<sizeof(T), alignof(T)> как deprecated и рекомендовали использовать вместо них конструкции alignas(T) std::byte t_buff[sizeof(T)];.
  • В P2255 добавили трейт для обнаружения передачи временного объекта на сохранение по ссылке. Это поможет на этапе компиляции ловить некоторые проблемы с std::tuple и std::pair.
  • В P2173 добавили синтаксис для применения атрибутов к лямбдам: [][[noreturn]]() { std::abort(); }.

Feature freeze


Комитет C++ состоит из шести основных групп:

  • Library Incubator (LEWGI);
  • Library Evolution (LEWG);
  • Library Wording (LWG);
  • Language Evolution Incubator (EWGI);
  • Core Language Evolution (EWG);
  • Core Language Wording (СWG).

Любое новое предложение должно пройти минимум через три из них: LEWGI -> LEWG -> LWG или EWGI -> EWG -> СWG. Так вот, LEWGI, LEWG, EWGI и EWG прекратили работу над С++23 и начали рассматривать предложения уже только для C++26. А значит, только года через три мы увидим следующие идеи:

  • Получение stacktrace из исключений;
  • Networking;
  • Reflection;
  • Полноценная библиотека для работы с корутинами.

При этом некоторые новинки уже прошли эти подгруппы и имеют шанс оказаться в C++23:

  • mdspan;
  • flat_map;
  • float16_t;
  • generator.

Вместо итогов


Если у вас есть идеи, как улучшить язык C++, — пожалуйста, делитесь с нами на сайте РГ21: stdcpp.ru. C++23 всё ближу к релизу, а значит, самое время рассказать о любимых багах и недочётах языка, чтобы мы могли отправить замечания к стандарту от России.

Ну и напоследок — 17 февраля мы проведём встречу РГ21, где расскажем о готовящихся новинках C++, поделимся инсайтами и ответим на ваши вопросы. Регистрируйтесь по ссылке.

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


  1. antoshkka Автор
    09.02.2022 11:41
    +2

    И сегодня как назло сломался сертификат для https://wg21.link/ . Ответственные предупреждены, скоро починят и ссылки на предложения заработают.


  1. x2v0
    09.02.2022 11:59

    Почему нет ни слова о Reflection?


    1. Coolrunner
      09.02.2022 12:11
      +8

      "А значит, только года через три мы увидим следующие идеи:

      ...

      Reflection;

      ..."


    1. bakhtiyarov
      09.02.2022 12:11
      +5

      Увы, слово есть...

      А значит, только года через три мы увидим следующие идеи:

      • Получение stacktrace из исключений;

      • Networking;

      • Reflection;

      • Полноценная библиотека для работы с корутинами.


      1. ReadOnlySadUser
        10.02.2022 10:37
        +2

        А с учётом того, что ещё есть лаг на реализацию + лаг на обновление тулчейнов, использовать это все получится только в 2028-2029 не раньше :) В общем, только наши внуки смогут отправить байтик по сети стандартным способом :)


  1. crackedmind
    09.02.2022 12:09
    +12

    • Networking;

    • Reflection;

    А может и не увидим ¯\_(ツ)_/¯


  1. Myxach
    09.02.2022 12:54
    +3

    for (const auto& val : {'Hello', 'world'} | std::views::join_with(", "))     std::cout << val;  // Выводит Hello, world  

    А точно ли тут нужен for, для банальной вещи как join?


    1. crackedmind
      09.02.2022 12:59
      +1

      Так for тут только для вывода.


      1. BeardedBeaver
        09.02.2022 13:14
        +2

        Не очень понял, какого типа тут val что для вывода нужен for


        1. antoshkka Автор
          09.02.2022 13:27
          +1

          Тип будет const char*

          Фактически будем итерироваться по диапазону {"Hello", ", ", "world"}


          1. crackedmind
            09.02.2022 14:03
            +3

            Тип будет join_view :) Но т.к. у него есть итератор, мы по нему и итерируеймся.


            1. inv2004
              09.02.2022 21:26
              +1

              Круто, конечно, но немного упущена идея почему в питоне это проще :) и на который ссылаются в данном примере


            1. lorc
              09.02.2022 21:55
              +1

              Ааа, т.е. join на самом деле не соединяет элементы контейнера? Может тогда лучше было назвать это interleave_with()?


              1. antoshkka Автор
                09.02.2022 22:04
                +2

                std::views ленивые и не делают промежуточных контейнеров. Так что и std::views::chunk, и std::views::zip, и std::views::take лишь ловко оперируют указателями и возвращают вам ссылки на нужные элементы в нужный момент.


                1. mapron
                  10.02.2022 04:23
                  +1

                  Подождите, а какой магией мне
                  const std::string helloWorld = join_something() получить-то?


                  1. antoshkka Автор
                    10.02.2022 09:13
                    +4

                    Вот так:

                    const auto helloWorld = container
                        | std::views::join_with(", ")
                        | std::ranges::to<std::string>()
                      ;


                    1. mapron
                      11.02.2022 07:37
                      +1

                      Actually, nice. Достаточно лаконично и вместе с тем всё еще сохраняет смысл, чтобы уже начинать использовать ЭТО а не велосипедный JoinVector() который есть в каждом среднем проекте :)


                  1. crackedmind
                    10.02.2022 09:51
                    +1

                    через ranges::to<std::string>

                    https://godbolt.org/z/1Wevr4xEW


                1. svr_91
                  10.02.2022 08:38
                  +3

                  Это как std::quoted, вроде и есть, а как использовать, непонятно


  1. LunaticRL
    09.02.2022 13:02
    +3

    Большое спасибо за статью. Конечно читать про все эти новинки здесь гораздо проще, чем постоянно мониторить cppreference или тот же реддит.

    Подскажите пожалуйста, я видел несколько интересных предложений от Герба Саттера на тему операторов as/is p2392 / (видео) и модификаторов аргументов функций in out inout move (видео) / рандомный пример кода

    А есть какая-то информация о том, в каком они статусе, и к какой версии стандарта их ждать, либо до какой их точно не ждать?


    1. antoshkka Автор
      09.02.2022 13:16

      Предложение на as/is было встречено положительно, но в C++23 pattern matching уже не попадёт. Моё предчувствие - идея пройдёт в стандарт C++26. А за прогрессом идеи можно наблюдать тут https://github.com/cplusplus/papers/issues/1064

      А по второй идее предложение ещё не рассматривали. Но мне кажется, что шансы на принятие - минимальны


      1. RiaD
        11.02.2022 21:59
        +1

        Удивлёе, что всем нравится as/is. По-моему с ним очень легко получать не то, что ты ожидаешь. Даже сам Herb набагал в слайдах, потому что думал, что is работает так, как логично, а не так, как он в реальности может работать

        Подробнее тут писал:

        PS: И в комменты на реддит не пришёл он похоже, как в блоге обещал


        1. antoshkka Автор
          11.02.2022 22:30

          Нравится потому что понятнее чем альтернативы:

            inspect (shape) {
              (as<Circle>    ? [r])   : return 3.14 * r * r;
              (as<Rectangle> ? [w, h]): return w * h;
            } 

          Хотя, на мой взгляд, с as/is тоже не идельно:

          inspect (shape) {
            [r]   as Circle    => 3.14 * r * r;
            [w,h] as Rectangle => w * h;
          }


          1. RiaD
            11.02.2022 23:04

            Против синтаксиса я ничего не имею, более того, считаю второй более человечным.

            Напрягает именно семантика того, как определяется разваливается в то, что просят или нет. Чтобы не было кейсов, когда что-то является int, но не является integral, например


  1. ncr
    09.02.2022 13:22
    +1

    В C++23 добавляется класс std::expected
    Добавляется, похоже, в сломанном виде.
    Ну ок, еще один std::regex.


    1. antoshkka Автор
      09.02.2022 13:46

      Хранить вторым аргументом исключение - это должно быть редким кейсом. Упор в std::expected сделан на хранение кодов ошибки - вы так получите тривиальность копирования expected, меньший размер объекта, более быструю передачу через регистры и т.п.

      А вот кидать код ошибки - это очень сомнительное удовольствие, лучше уж кинуть что-то отнаследованное от std::exception, а именно bad_expected_access. Ну и ловить в коде тогда можно весьма ожидаемый std::exception, а например не srd::errc.

      Что же касается operator* - в дебаге там будет assert, который поможет вам поймать проблему в тестах. В C++ operator* всегда является небезопасным доступом, и программист в ответе за проверку. Хотите чтобы стандартная библиотека делала проверку за вас - используйте value(). Если менять устоявшееся правило только для одного класса то будет только хуже - возникнет путанница.

      Ну и наконец, это же C++. Не нравится стандартный std::expected - напишите и используйте свой, никто не заставляет пользоваться тем, что не подходит под ваши конкретные нужды.


      1. ncr
        09.02.2022 15:05
        +3

        Хранить вторым аргументом исключение — это должно быть редким кейсом
        Это было основным кейсом.
        Упор в std::expected сделан на хранение кодов ошибки
        У меня есть некоторые сомнения в целесообразности упоров на коды ошибок в стандартной библиотеке, в целом построенной вокруг исключений.
        вы так получите тривиальность копирования expected
        Тривиальность копирования как бы зависит не только от E, но и от T.
        кидать код ошибки — это очень сомнительное удовольствие
        С этим невозможно не согласиться. Если ими не пользоваться, то и кидать их не придется.
        Если менять устоявшееся правило только для одного класса то будет только хуже
        Если рассматривать expected просто как advanced optional — несомненно. Проблема в том, что это был не совсем advanced optional.
        Не нравится стандартный std::expected — напишите и используйте свой
        О чем и речь.


        1. antoshkka Автор
          10.02.2022 00:15

          Это было основным кейсом у Александреску. Однако большинство людей в комитете весьма обоснованно решили, что:

          • кидать int/enum -- жуть и будет проскакивать мимо всех пользовательских catch(const std::exception& e)

          • обязывать пользователей всегда хранить тип, отнаследованный от std::exception -- повлияет на производительность std::expected, из-за vptr+код+флаг он перестанет влезать в регистры для возврата и компилятор начнёт возвращать его через стек

          Если вы видите рабочий выход из этой ситуации -- предлагайте рабочее решение, отправим его замечанием к C++23 от России.


          1. ncr
            10.02.2022 02:52
            +2

            кидать int/enum — жуть
            Жуть. Не используйте int/enum в качестве исключений.
            обязывать пользователей всегда хранить тип, отнаследованный от std::exception — повлияет на производительность
            Стандарт вроде бы нигде не обязывает пользователей наследовать все исключения от std::exception, так с чего бы обязывать здесь? Пользователь как бы сам в состоянии определиться, по карману ему там std::exception или нет.
            предлагайте рабочее решение
            Я не очень понимаю, что тут предлагать. Изначально это был именно throw exception, но отложенный во времени и пространстве, и в этом была вся фишка. При натягивании его на коды ошибок получилось что-то совсем другое. Оно, возможно, тоже имеет право на существование и найдет применение, но фишка утеряна.


            1. antoshkka Автор
              10.02.2022 09:50
              +2

              А давайте действительно пофорсим фикс через коментарий от страны. В предложении есть замечание, что возможна кастомизация выкидывания исключения, но в данный момент её не предлагают.

              Завёл тикет https://github.com/cpp-ru/ideas/issues/509

              Добавьте плиз в тикет примеров/мотивации/деталей/...


      1. belator
        09.02.2022 17:21

        Ну и наконец, это же C++. Не нравится стандартный std::expected - напишите и используйте свой, никто не заставляет пользоваться тем, что не подходит под ваши конкретные нужды.

        Почему комитет игнорирует гугловый Status и StatusOr, проверенные годами на продакшене классы для обработки ошибок?


        1. antoshkka Автор
          09.02.2022 17:51

          В комитете есть ребята из гугла, но они не торопятся предлагать подобное, а вместо этого голосуют по предложению expected. Может Status и StatusOr не так ужи и хороши?


          1. belator
            09.02.2022 19:18

            Status имеет намного более лучшую производительность в сравнении с этим предлагаемым интерфейсом:

            http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r11.html#expected.expected


            Для сравнения:
            https://github.com/abseil/abseil-cpp/blob/master/absl/status/status.h#L658

            где самые частые ошибки могут просто жить внутри младших битов uintptr_t


            1. antoshkka Автор
              09.02.2022 19:54

              В стандарте прописывается интерфнйс а не реализация. Слова "exposition only" в предложении не спроста стоят. Так что ничего не запрещает оптимизацию из abseil использовать в реализации стандартной библиотеки.


            1. myxo
              09.02.2022 20:26

              А что такое «самые частые ошибки»? В expected тип ошибки параметризуемый.


      1. belator
        09.02.2022 17:22
        +1

        Что же касается operator* - в дебаге там будет assert, который поможет вам поймать проблему в тестах. В C++ operator* всегда является небезопасным доступом, и программист в ответе за проверку. Хотите чтобы стандартная библиотека делала проверку за вас - используйте value(). Если менять устоявшееся правило только для одного класса то будет только хуже - возникнет путанница.

        Почему тогда нельзя получить unsafe значение из std::variant? Почему только либо get_if либо исключение?


        1. antoshkka Автор
          09.02.2022 17:59

          На operator*() никак std::variant не ложится, а std::visit покрывает большинство кейсов когда нужен непроверенный доступ. Если у вас другие кейсы и непровереный доступ вам нужен - пишите предложение для включения в стандарт, поможем с защитой идеи.


          1. belator
            09.02.2022 19:04

            Например, здесь https://source.chromium.org/chromium/chromium/src/+/main:base/values.h;l=631

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

            Нужен обязательно какой-то std::get_unsafe().


            1. antoshkka Автор
              09.02.2022 19:58

              В примере везде используется std::get, который кидает исключение при попытке достать неверный тип. Замена на get_unsafe кардинально изменит поведение типа


              1. belator
                10.02.2022 16:42
                +1

                Во-первых, в хроме приняли решение, что они хотят крашить процесс, если произошла попытка достать неверный тип. Так что не стоит смотреть, как сделано сейчас.

                Во-вторых, раньше был union и при получении не того типа был UB, но обычно перед получением значения проверялся тип с помощью is_* методов.

                Вот для данного случая и пригодился бы get_unsafe().


                1. antoshkka Автор
                  10.02.2022 17:10
                  +1

                  Ок, уговорили. Если сделаете черновое предложение по инструкции - поможем с его доведением до ума и продвижением в комитете


      1. Rahl
        09.02.2022 21:51

        А std::error_code вторым аргументом имеет право на жизнь?


        1. antoshkka Автор
          10.02.2022 09:15

          Да, там может быть что угодно, хоть std::vector


  1. Un_ka
    09.02.2022 13:29

    В P0627 добавили функцию std::unreachable() для информирования компилятора о недостижимых участках кода (таких, куда программа никогда не заходит во время своего выполнения).

    И что компилятор с этим будет делать? Не будет компилировать этот участок или при его достижении программа выбросит ошибку, что туда нельзя?


    1. mayorovp
      09.02.2022 13:37
      +1

      Что хочет, то и будет делать. Но, скорее всего, не будет компилировать этот участок, а все условия которые "ведут" в него будет считать ложными.


    1. DarkEld3r
      09.02.2022 13:39
      +4

      И что компилятор с этим будет делать?

      Компилятор сможет производить дополнительные оптимизации полагаясь на то, что эта ветка кода никогда не выполнится.


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

      При достижении будет UB.


      1. AntonioMichaelAlvarez
        09.02.2022 14:36

        Прошу простить меня за невежество, но какой вообще может быть смысл в таком операторе? Зачем писать (или оставлять) недостижимый код, а потом же помечать его недостижимым? Разве не будет лучшим вариантом вообще не писать код?


        1. KanuTaH
          09.02.2022 14:49

          Это то же самое, что __assume(0) из MSVC, только стандартное.


          1. ncwca
            09.02.2022 16:55
            +3

            Это обёртка над тем, что уже тысячи лет в нормальных компиляторах, а именно __builtin_unreachable


        1. ncwca
          09.02.2022 17:10
          +4

          Тем, что он влияет на анализатор. Точно так же как и throw. https://godbolt.org/z/fshW7Wodz - максимально простой пример. Конечно, в реальности контексты использования более сложные, но суть такая же.

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

          Так же в некоторых случаях компилятор просто не может вывести это из кода. Допустим из произвольного asm. Тот же noreturn применяется для того же.

          Конечно, куда лучше было бы ограничить это где-то сверху и далее информацию передать через типы, но такого нет.

          Предположим, что код с интами работает быстрее, а отрицательные числа нам ненужны. Заменить на uint32_t нельзя - будет медленее. Но компилятор всегда будет предполагаеть наличие их.

          Поэтому можно сделать if(x < 0) __builtin_unreachable(); либо if(x >= 0) else __builtin_unreachable()

          Это поможет куда лучше оптимизировать код.


  1. myxo
    09.02.2022 14:03
    +3

    А что с модуляризацией стандартной библиотеки? Про это вообще нигде не пишут.

    Полноценная библиотека для работы с корутинами.
    это имеется в виду std::executor? Жаль, что не прошел. Там какие-то проблемы нашли или просто не успели?


    1. crackedmind
      09.02.2022 14:07
      +1

  1. koowaah
    09.02.2022 14:12
    +1

    Интересно узнать, почему не завезли такие возможности.
    constexpr class

    static operator()

    Portable assumptions - [[assume(condition)]]

    #warning

    Вот читал в документе, и казалося что должны добавить.
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1018r14.html#P2350r2


    1. antoshkka Автор
      09.02.2022 14:18
      +1

      Все эти вещи успели проскочить нужные подгруппы и есть все шансы увидеть их в C++23


      1. koowaah
        09.02.2022 15:38
        +1

        Спасибо.


  1. humanzer0
    09.02.2022 14:15
    +1

    А std::ranges::zip будет?


    1. crackedmind
      09.02.2022 14:18
      +1

      Его еще в октябре одобрили.


    1. antoshkka Автор
      09.02.2022 14:19
      +1

      Будет, приняли в стандарт в прошлый раз: С++23 — feature freeze близко


  1. koowaah
    09.02.2022 14:19
    +1

    Интересно узнать, есть ли какие-то продвижения по контрактах?
    Хотелося б иметь такое в стандарте.


    1. antoshkka Автор
      09.02.2022 16:16
      +1

      Их готовятся добавлять по кусочкам в стандарт. Например на подходе [[assume(x)]]


  1. vt4a2h
    09.02.2022 14:19
    +2

    • std::expected — новый механизм сообщения об ошибках без использования исключений и без недостатков кодов возврата.

    Хорошая штука, аналоги которой есть во многих библиотеках. Жаль только, что хотя бы без аналога оператора "?" из Rust, использовать его не так удобно. Может быть к C++ 29 и появится (будем верить, что без префикса вроде "co_").

    К слову, pattern matching тоже неплохо бы работал с std::expected. Но тут, на мой взгляд, всё очень сильно неопределено (касательно реализации сопоставления с образцом в C++).


    1. ncwca
      09.02.2022 17:25
      -5

      ? - это костыль, который лишь говорит о том, где все сказки "удобно, пм - круто" были фейком. Можно почитать то, что пели последователи result до ?.

      Если говорить о реальном коде, особенно о C++(где есть полиморфизм и куда более мощная ситема типов, нежели в раст), то ? становиться бесполезным.

      Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать {first::f()?; second::f()?;} - код сломается. Там есть страшные костыли на макросне, но в реальном коде просто будет box dyn err. А здесь уже проще написать исключения.

      К слову, pattern matching тоже неплохо бы работал с std::expected.

      pm достаточно слабая концепция, которая во много неполноценна. А уж тем более в C++, если есть полиморфизм и перегрузка.

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

      Одна из причин - не расширяемость. pm работает всегда только по закрытому типу, который зачастую объявлен где-то в кишках какой-то библиотеки. Расширить его нельзя. Никак.

      Трейт/перегрузку(трейты в расте это такая попытка реализовтаь перегрузку из цпп) это делать позволяют. Т.е. где-то в пользовательском коде можно написать impl чего-то, либо перегрузку.


      1. vt4a2h
        09.02.2022 18:16
        +1

        ? - это костыль, который лишь говорит о том, где все сказки "удобно, пм - круто" были фейком. Можно почитать то, что пели последователи result до ?.

        Если говорить о реальном коде, особенно о C++(где есть полиморфизм и куда более мощная ситема типов, нежели в раст), то ? становиться бесполезным.

        Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать {first::f()?; second::f()?;} - код сломается. Там есть страшные костыли на макросне, но в реальном коде просто будет box dyn err. А здесь уже проще написать исключения.

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

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

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

        pm достаточно слабая концепция, которая во много неполноценна. А уж тем более в C++, если есть полиморфизм и перегрузка.

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

        Вы имеете ввиду реализацию pm непосредственно в Rust?

        Просто в целом, это довольно известная, проверенная временем и широко применяющаяся концепция, например в функциональных языках программирования.


        1. ncwca
          09.02.2022 18:36
          -4

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

          Заменять 2-3строчки на одну - это всегда такая себе затея. Она превращает язык в помойку. Когда бездумно добавляется сахар ради сахара.

          Если на языке можно реализовать ? - это хорошо. Если же ? это просто костыль на уровне компилятор, то это плохо. В язык нужно добавлять возможности через которые уже реализуется сахар. А не просто сахар.

          Потому добавление сахара - это проблема. И потому, что весь не добавишь. И потому что это идёт в ущерб фичам. Здесь достаточно посмотреть на раст. Где примитивного саха много, а фичей мало.

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

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

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

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

          Это то самое box dyn err.

          Вы имеете ввиду реализацию pm непосредственно в Rust?

          Везде, особенно в раст. Да, в более-менее адекватных фп-языках уже давно эмулируют перегрузку через pm. Это куда удобнее, чем искатаь match в лапше. Но там есть всё те же проблемы с тем, что их нельзя расширять из пользовательского кода.

          Просто в целом, это довольно известная, проверенная временем и широко применяющаяся концепция, например в функциональных языках программирования.

          Проблема только в том, что на функциональных языках программирования ничего не написано. А что пишется - там уже работает естественный отбор.

          Допустим, каждый последователь расскажет, что у него там "чистый фп-язык" - все дела. Но в реальности, когда он идёт писать код - всё забывается. И уже язык становиться мультипарадигмальным, а массив всегда был в фп.

          Неважно что "ты" считаешь и как думаешь. Есть то, что работает, а что не работает. И когда кто-то начинает что-то делать - реальность всегда вносит коррективы. И вот фп уже не фп. И пм уже не пм.


          1. mayorovp
            10.02.2022 00:58

            Если на языке можно реализовать? — это хорошо. Если же? это просто костыль на уровне компилятор, то это плохо. В язык нужно добавлять возможности через которые уже реализуется сахар. А не просто сахар.

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


            А оператор? — это не столько костыль, сколько сокращение для часто используемой операции.


            1. ncwca
              10.02.2022 16:31
              -5

              Вот, здесь тоже такое же враньё и прпоагандистская херня.

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

              Здесь пропагандист мусорной скриптухи подменяет тезис. Я говорил именно о ?, а не какой-то макросне. Эта макросня пишется и на сишке. И да, макросня не является языком. И не является языковыми возможностями.

              Далее типичная история пропагандиста, который пытается делать вид, что я чего-то не знаю. Я поищу пруфы. https://habr.com/ru/company/yandex/blog/580880/comments/#comment_23564896 - вот пруф.

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

              А оператор? — это не столько костыль, сколько сокращение для часто используемой операции.

              Нет, это именно костыль. И говорял я именно о нём, а не о чём-то другое. Поэтому данный пропагандист идёт и показывает реализацию ? на скриптухе. Не `if(expr = err) return expr.err` в макросе, а ?


      1. mayorovp
        10.02.2022 00:53
        +1

        ? — это костыль, который лишь говорит о том, где все сказки "удобно, пм — круто" были фейком. Можно почитать то, что пели последователи result до ?.

        А что именно они пели? Мне вот необходимость подобного оператора была ясна с самого начала, и я знал что однажды он появится.


        Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать {first::f()?; second::f()?;} — код сломается.

        Ну вот у меня в моём коде нечто подобное как раз написано. Первая функция возвращает std::io::Error, вторая — nix::Error. И, представляете, оно работает! Ничего не сломалось!


        pm достаточно слабая концепция, которая во много неполноценна [...] Поэтому в том же расте за пределами очевидных учебных примеров pm используется редко. Везде используются трейты.

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


        Одна из причин — не расширяемость. pm работает всегда только по закрытому типу, который зачастую объявлен где-то в кишках какой-то библиотеки. Расширить его нельзя. Никак.

        Как я уже сказан, паттерн-матчинг расширяем по операциям. Возвращаясь к Result — ну нет никакого смысла "расширять" снаружи это перечисление, в нём всегда Ok и Err, третьего быть не может в принципе. И коды ошибок, возвращаемые библиотекой, тоже незачем расширять снаружи библиотеки. А вот обрабатывать эти коды надо во многих местах, и вынести все операции в интерфейс/трейт/что-то ещё вы не сможете.


        трейты в расте это такая попытка реализовтаь перегрузку из цпп

        Нет, трейты — это такая попытка реализовать полиморфизм. Успешная попытка, к слову.


        1. 0xd34df00d
          10.02.2022 03:26
          +5

          Спорить с очередным аккаунтом Царя про плюсы и раст ­— не очень продуктивная трата времени.


          1. ncwca
            10.02.2022 19:41
            -6

            Кстати, сектанты не палятся. Многие люди не понимают, когда я пишу "да это просто клоуны, обужиенные, которых я не раз глушил - они просто бегают и гадят". Им непонятно как так.

            Они обычно шлангуют и несут херню видя "да мы тебя не знаем - мы просто минусуем за что-то". В этот раз они охренели совсем и решили забить на конспирацию.

            А, ещё эти клоуны часто рассказывают куллстори про личности, ад-хоминем и прочие куллстори. А теперь они просто признаются "мы будем гадить тебе за то кто ты, а не за то что ты пишешь". Да и гадят они не за то, кто я. А за то, что они множество раз плакались в наших спорах. И это - единственное, что им остаётся делать. Просто нести херню и гадить.

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


            1. 0xd34df00d
              10.02.2022 21:37
              +2

              Я лично не гажу и, например, в этом треде не поставил ни одного минуса вам (как ещё на хабре-то гадить), но просто обсуждать с вами языки программирования — гиблая затея, потому что у вас достаточно много заблуждений, за которые вы очень крепко держитесь. Это было интересно первые пару раз, но потом уже как-то скучно.


              1. ncwca
                10.02.2022 21:57
                -3

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

                Ну и рассуждения про "забудлежения" типичная херня. Типичный мейнстримный балабол, который не состоялся qt/си с классами джуном и бегает везде и всюду и пытается через облизывание маргинальной херни набрать очки. Конкурировать с лучшими сложно, поэтому всегда хочется побежать в какой-нибудь хаскель, где обитает всякая студентота и прочие неудачники. Авось там кто заметит. И вот ты уже не на побегушках на какой-то цпп-галере, а имеешь шанс на заметить.

                Уровень познаний этого персонажа можно посмотреть в комментах под его клоунадой. Допустим там, где он в очередной раз побежал цпп, потом опозорился, начал мазаться и до сих пор не смог родить атомики.

                Подобные персонажи живут за счёт того, что коменты никто не читает. Поэтолму нести можно какую угодно херню.

                При этом на хабре часто выпиливается этот позор. Множество моих комментов было выпилено. Всякие позорные темы(типа rust vs swift) авторы выпиливают вместо с собою. А там такое позорище было. Жалко, что вебархив сохранил только начала позора. Но кому интересно может поискать. там и начала достаточно.

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


                1. 0xd34df00d
                  10.02.2022 22:22
                  +1

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

                  Ну зачем вы так?


                  Скриншоты, я так понимаю, вас не устроят, поэтому для доказательства того, что я никуда не гадил, я после написания этого комментария возьму девять произвольных комментариев и продемонстрирую, что на их оценку я не влиял (так что счёт минусов там увеличится).


                  Остальное обсуждать бессмысленно, потому что опять везде у вас какие-то сектанты, балаболы и методички.


                  1. ncwca
                    10.02.2022 23:07
                    -3

                    Как же нелепо. Просто съехал с темы. Типичная тактика сектанта - я уже каждого поймал на этом.

                    В данном случае всё происходит по тому же сценарию. Берётся выдерается кусок моей фразы, а далее начинается балабольство "я не минусовал". При этом как будто бы я утверждал, что данный персонаж что-то минусовал. Да и минусы можно отменить, насколько я знаю.

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

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

                    Ах ну и да. Этот сектант прибежал и начал рассказывать "он ничего не понимает - он лох". Ему это делать можно. Низшие касты сектантов - тут же побежали плюсовать и гадить мне.

                    Остальное обсуждать бессмысленно, потому что опять везде у вас какие-то сектанты, балаболы и методички.

                    Вообще какие-то доказательства после этого бесмысленно. Здесь риторика типичного сектанта с синдромом бога, где он - есть мир, а мир есть он и его секта.

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


        1. ncwca
          10.02.2022 15:30
          -3

          Типичная клоунада, показываю мат в один ход.

          Ну вот у меня в моём коде нечто подобное как раз написано. Первая функция возвращает std::io::Error, вторая — nix::Error. И, представляете, оно работает! Ничего не сломалось!

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

          Этот ответ полнейшая чушь, потому как это не работает. На что расчитывает данный пропагандист? Правильно, на то что никто не прочитает. Что он выдернет кусок фразы и будет спорить, но проблема в том, что я нигде не говорил, что оно НЕ РАБОТАЕТ вообще. Я говорил о том, что оно не работает с заявляемыми качествами и не работает без костылей.

          Покажу как выглядит этот тезис полностью:

          Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать {first::f()?; second::f()?;} - код сломается. Там есть страшные костыли на макросне, но в реальном коде просто будет box dyn err. А здесь уже проще написать исключения.

          Т.е. я сказал, что там есть и box dyn err костыли, и что есть такие же на макросне. Как же удобно быть пропагандистом этой мусорной скриптухи, когда ты можешь врать, пастить куски фраз. И убогие тебя будут плюсовать, а меня минусовать.

          А теперь смотри на то, как данный пропагадист потеряется. Теперь он покажет "работает" без макросни и без dyn err, т.е. любой потери типовой информации.

          Ну и да, пусть этот пропагандист объяснит почему же он спастил обрывок фразы и куда потерялось дополнение?


          1. mayorovp
            10.02.2022 16:19

            А очень просто оно работает:


            #[derive(std::fmt::Debug)]
            pub enum MyError {
                IoError(std::io::Error),
                NixError(nix::Error),
            }
            
            impl From<nix::Error> for MyError {
                fn from (x: nix::Error) -> Self {
                    MyError::NixError(x)
                }
            }
            
            impl From<std::io::Error> for MyError {
                fn from (x: std::io::Error) -> Self {
                    MyError::IoError(x)
                }
            }
            
            // …
            
            fn first() -> std::result::Result<(), nix::Error> { std::unimplemented!() }
            fn second() -> std::result::Result<(), std::io::Error> { std::unimplemented!() }
            
            fn example() -> std::result::Result<(), MyError> {
                first()?;
                second()?;
                Ok(())
            }

            Найдите тут хоть один dyn или макрос или покажите где именно теряется информация.


            1. technic93
              10.02.2022 17:35
              -2

              Один бокс потенциально есть внутри

              std::io::Error

              Макрос тоже есть в первой строчки вашего снипетта ;) Но писать эти строки с From обычно лень и берут `thiserror` макрос.


            1. ncwca
              10.02.2022 17:38
              -4

              Боже, какая нелепая клоунада. Данный пропагандист просто раскрыл мусорный макрос руками.

              #[derive(std::fmt::Debug)]
              pub enum MyError {
                  IoError(std::io::Error),
                  NixError(nix::Error),
              }
              
              impl From<nix::Error> for MyError {
                  fn from (x: nix::Error) -> Self {
                      MyError::NixError(x)
                  }
              }
              
              impl From<std::io::Error> for MyError {
                  fn from (x: std::io::Error) -> Self {
                      MyError::IoError(x)
                  }
              }

              Эти мусорные костыли то, о чём я говорил и что генерирует макрос. Правда это убожество бездарное в сравнение с макросами, но хоть что-то.

              Очевидно, что без этого дерьма оно не работает. Что было мною доказано. Кому интересно - я выше там давал ссылку, где я более подробно разбирал всю эту чушь этих клоунов.

              Ладно, мне максимально лень раз в час что-то отвечать в этой помойке.


            1. technic93
              10.02.2022 18:03
              -2

              На самом деле проблема такого подхода возникает когда есть много разных ошибок. Например изначально есть ошибки A, B, C, D. Дальше есть функция x(), которая вызывает функции с потенциальными ошибками A, B и функция y(), которая вызвает ошибки с вариантами A, C, D. Впринципе можно предположить что A это какая-то ошибка более частая - то же io, а B, C, D что то более конкретное доменное. Воощем в итоге получается что у нас `enum X { A, B }` и `enum Y { A, C, D }`. потом появляется функция z() которая вызывает x()? и y()? ... Хорошо делаем дальше `enum Z { X, Y }`... В итоге чтобы найти в этой иерархии наш начальный A приходится ходить внутрь дерева енумов 10ью разными путями. Сделать из дерева плоскую форму ошибок, перегруппировать её, - таких средств нам раст не даёт. Вообщем на третьем-четвёртом уровне вложености всем надоедает, и делают dyn Box (которого вы обещали что не будет)... Люди пишут блоги с какими-то мантрами про то когда на самом деле нужно боксить а когда нет, наплодили десяток либ с макросами, чтобы упростить эту лапшу енумов с From, match и map_err. А в итоге среднестатистческий код на расте не состоит на 90% из обработки ошибок, лишь потому, что используется механизм исключений из С++ спрятанный за макросом panic!.


  1. koowaah
    09.02.2022 14:22
    +1

    Можете подсказать, ведуться какие-то работы по добавления, аналога gsl::non_null?
    https://github.com/microsoft/GSL/blob/main/include/gsl/pointers
    Было б класно также, иметь и nullable в парочку.


    1. antoshkka Автор
      10.02.2022 16:59

      Работы ведутся только на уровне отдельных тулчейнов/компиляторов. В стандарт пока рано включать - это не самая популярная фича и есть проблемы с диагностикой


  1. koowaah
    09.02.2022 14:26
    +1

    А есть ли какие-то продвижки по pattern matching?


  1. Myxach
    09.02.2022 14:39

    В P0627 добавили функцию std::unreachable() для информирования компилятора о недостижимых участках кода (таких, куда программа никогда не заходит во время своего выполнения).

    А чем отличия от ifdef или препроцессинг это уже говнокод?


    1. antoshkka Автор
      09.02.2022 16:22
      +2

      Препроцессором такого не достичь:

      int foo(int i) {
          switch (i) {
            case 42: return 64;
            case 142: return 6;
            case 1024: return 0;
          }
          // Без следующей строчки компилятор будет сыпать предупреждениями
          std::unreachable();
      }


  1. LunaticRL
    09.02.2022 14:48
    +1

    Вопрос немного не по теме, но все же:

    Насколько я понимаю модули из C++20 сейчас на этапе внедрения. В компиляторах они поддержаны: в gcc на ~90% и ~70% в clang.

    Но билд системы пока не особенно брались за поддержку: тот же CMake в основной ветке вроде пока никак под модули не адаптировался.

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


    1. antoshkka Автор
      09.02.2022 16:29
      +1

      Плохая поддержка в компиляторах - основной стоппер. Тот же Boost пока не внедрил модули, в частности потому что у большинства разработчиков на их машинах в компиляторах модули просто не работают.


      1. LunaticRL
        09.02.2022 16:40
        +2

        Понятно, спасибо)


  1. koowaah
    09.02.2022 14:51
    +1

    А есть ли какие-то продвижки по предложению Герба Саттера - static exceptions?
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0709r4.pdf


    1. antoshkka Автор
      09.02.2022 20:24
      +1

      К предложению есть серьёзные возражения https://wg21.link/p1947r0 и много вопросов по поводу расширяемости на пользовательские типы. Пока проблемы не будут решены - предложение не пройдёт... после этого может тоже не пройти. К тому же один из разработчиков executors планировал сделать заход на исключения, может придумает что-то кардинально лучшее.


      1. ncwca
        10.02.2022 01:48
        -5

        Это никак не решить. Там слишком сильно. Правда непонятно почему это критика статических исключений. Это критика того мусора, которы пытаются выдать за них. И попытка защититься от всякой скриптуха-пропаганды на тему "исключения говно".


        Никаких возражений именно на тему статических исключений там нет. Просто статический исключения - это развитие обычных, их оптимизация. Без ущерба фунrциональности(как любит делать скрипту-пропаганда. Выдавая какой-то дырявый мусор за решение проблемы. Типа result,БЧ и прочий мусор).


        А именно что статический исключения на текущем уровне развития C++ невозможно. В массе своей этот набор дырявых костылей поверх си.


        Я как раз рассказывал о том, что rtti тормозной мусор именно из-за линковки и прочей сишной атрибутики. Оказывается всё это уже обсуждается, а на меня смотрели с круглыми глазами.


        Кому интересно я повторю. Из-за того, что у нас любой T является открытым типом мы никак не можем реализовать нормально rtti, только через строки. Т.е. сами типы в рантайме и их сравнение - это километры строк и их сравнение. В языках с vm мы можем просто заменить всё это на, условно, int. Потому что вм управляет всеми типами существующими в языке.


        Аналогично это можно сделать и на C++ сейчас. Если выпилить мусорную линковку, которая итак не работает в С++ сейчас, поэтому все библиотеки являются ho, а всё остальное - си с классами. И сказать компилятору, что другого кода нет(аля -fwhole-program). Тем самым закроются все типы.


        Таким образом любой тип - это int, а любое сравнение - сравнение интов. Аналогично можно буду работать что-то типа `any{}.visit([](auto && x) {});`


        Особенно с этим не будет никаких проблем в ембедед, где это сделать элементарно(о чём автор и пишет). Но адепты хотят ныть, рассказывать враньё про rtti и исключения, вместо осознания и понимания проблем.



        Так же здесь не будут работать всё эти сказки про "а как же большие программы". Такие же истории были про lto, ведь этот костыль(lto) решает ту же проблему. Без проблемы сделали после сделали "параллельное" лто. Тоже самое можно сделать на уровне компилятора. И это не такая уж большая проблема.


        По-сути сейчас любая ide решает ту же проблему - как парсить куски исходника отдельно? Обычно это не доходит дальше хедеров, но здесь просто в тему не вкладываются.


        В любом случае это нужно сделать и никак далее с линковкой С++ жить не сможет. Либы будут всё сложнее и компиляция будет длится вечно уже на текущем этапе и на хеловоролде.


        Даже в рамках микса С++ и си с классами линковка несостоятельна. Потому как результате С++-код разбираться и компилируется десятки, сотни раз. И здесь не могут всякие pch, потому основное время часто занимает инстанцирование и кодогенерация, а не парсинг как таковой.


        Поэтому любая раздельная сборка ~95% времени собирает одно и тоже, а не ваш код. Это пытались как-то чинить всякими костылями типа jumbo/unity билдов.


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



        lto - это вообще диверсия всякого скама типа раста. Когда ресурсы людские тратятся на "вроде как" универсальные решения. И люди верят этом, но это не так. Это просто рождает всякий скам, который способствует деградации области. lto нужен всяким скриптухам с низким уровнем человеческого капитала. Какая разница что там у убогих? Которые, к тому же, прибегают тебе в комменты и гадят?


        Решение это проблемы на уровне языка - открывает множество возможностей, делает ненужным всякие костыли типа lto. И это большая проблема на самом деле. И она везде.



        У нас есть, условно, умный и глупый. И вместо того, чтобы поддерживать умного и призывать/способствовать развитию глупого - все всеми силами пытаются глушить умных. Шаблоны? Зачем шаблоны - запретить нахрен. Ведь я их не понимаю, поэтому сжечь - сжечь их, сжечь этих ведьм. Невежество правит миром.


        Другие не могут? У других нет возможностей? Мы должны быть такие же. нам ненужно. Не выделяйся. Это то, что нужно понять. Лучше всегда можно свести к худшему, но не наоборот.


        Вот адепты си с классами, адепты цпп98 и прочего. Постоянно хейтят возможности крестов, прогресс. Прикрываясь какой-то свободой, какой-то чистотой(расы). Вся их мотивация - это, конечно же, защита своей кормушки. Ладно все привыкли друг другу врать, и делать вид, что какая разница. Но с таким подходом мы никуда не придём.


        Люди падают, падают жертвами этой пропаганды. Начинают действительно верить в том, что должен быть выбор, что это как-то спорный вопрос. Но нет. Здесь нет ничего спорного. Здесь нет никакого выбора - вас обманули.



        Что теряют адепты си с классами? Ничего. Они ничего не теряют. Им никто не запрещает не использовать все старые возможности. Но при этом другие получают возможности, которые нужны всем.


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


        Но почему же они недовольны? Я уже сказал, но они не скажут. Они недовольны именно тем, что завтра они потеряют работу. Потому что они уже не могут говорить "мы знаем С++", "мы и С++ - это целое", "мы - представляем С++". Тот, кто их нанимает будет видеть, будет видеть код на новом языке. Код лучше, код чище, код проще. Код людей, которые желают развиваться. И эти люди поймут, что их обманывали. Поймут, что нужно выкинуть баласт. Это их страх.


        Поэтому они пытаются загнать нас в это болото. Чтобы у нас ничего не было. Чтобы мы барахтались в этом дерьме и бились, бились с ними на фронте этого невежества. Бились по их правилам.



        Поэтому лучше всегда сделать вначале мощнее, фичастее, а потом уже ограничивать для определённых групп. Потому как ограничить всегда можно, а расширить нет. Очень хороший пример - это tcp-убожество. Людей действительно защищают этот мусор, который во всём хуже. Вместо того, чтобы на уровне транспорта оставить то, что даёт максимальную свободу. Оставить просто пересылку данных. А уже поверх этого строить то, что нужно.


        И доводы там такие же "ой, наше сокет-дерьмо тормозит, потому что наше ядро, api, подходы и прочее - дерьмо". Но это не проблема. Это проблема того, что изначально был выбран мусор в качестве базы, а после все было заточена на него. Поэтому будут боль перехода, но эта боль - это не проблема нового. Этого проблема старого.



        Такая же ситуация с теми, кто хочет повесить на остальных своё дерьмо. Допустим, у тебя есть легаси мусор. Ты не хочешь его обновлять? Ты не хочешь в него вкладываться. Какое решение? Сиди на старом компиляторе. Но эти воры хотят украсть у вас, хотят на вас повесить поддержку своего дерьма.


        Они постоянно уверяют вас в том, что поддержка нужна. Что нужно тащить всё это в компиляторе и языке. Но на самом деле это просто паразиты и они пользуются слабостью людей. Никаких целей, кроме как украсть у вас - у них нет.


        В какой-то степени люди начинают это понимать, но мало. Это тоже самое что выше. Пропаганда и адепты невежества хотят, чтобы вы платили за них. Чтобы вы, способные к большему - копались в дерьме потому, что адепт невежества не может в то, что можете вы. Адепты невежества хотят, чтобы вы платили налог. Чтобы весь новый код, всё что вы пишите - страдало и платило, платило тот самый путём того, что вы не используете новое, лучшее.


        Это защищает мусор от конкуренции. Почему они всегда орут "пиши на дерьме", "пиши дерьмо", "пиши как в 98". Потому что они хотят, чтобы вы были в том же болоте, что и они, повторюсь. Чтобы они могли взять ваш код, чтобы за поддержку их мусора для вашего кода заплатили ВЫ, а не ОНИ.



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


        Допустим, они пытаются на генериках делать компилтайм и nttp - это невозможно. Но они будут в это верить и будут пытаться. Как раньше они все рассказывали про "инстанцирование - это мусор". И потом через 10 лет они, возможно, дойдут до проблемы.



        Такая же проблема есть и у С++, когда "проблемы" пытаются решить всякими костылями игнорируя то, почему "плохо" работает "плохо" и плохо ли вообще. Об этом написано в тех возражениях - можно почитать.


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



        И ещё одно. Язык не должен сохранять какое-то abi и прочий мусор. Это, опять же, налог на развитие. Совместимость не означает, что что-то должно быть реализовано так же, как раньше - это ещё одна ложь.


        Я когда-то приводил простой пример. Если мы заменим функции в С++ на нормальный, то эти функции могут, в том числе, эмулировать старое сишное поведение. И пусть там любители нырять в дерьмо в него ныряют, но мы не будем.


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


        Аналогично нельзя альтернативу. Всегда хлебай дерьмо. Альтернативные исключения? Хрен. Альтенативные функции? Хрен. Альтернативное хоть что-то? Хрен. С этим живи. Всегда. Это цпп.




        1. eshirshov
          10.02.2022 08:45
          -1

          это не комментарий))
          это целая статья!!
          затравка для holy war


  1. koowaah
    09.02.2022 14:52
    +2

    Очень интересное предложения - std::embed. Если шанс что такое завезут в C++23/C++26?

    http://open-std.org/JTC1/SC22/WG21/docs/papers/2020/p1040r6.html


    1. antoshkka Автор
      09.02.2022 20:14

      Завезут, но в C++23 не успели.

      До тех пор придётся пользоваться заменами, на подобие https://github.com/graphitemaster/incbin


  1. amarao
    09.02.2022 15:19

    std::expected<int, std::errc> to_int(std::string_view str) {

    Подозрительно напоминает

    fn to_int(inp: &str) -> Result<i32, err:ErrType> {

    Но! Во втором случае есть #[must_use]


    1. vt4a2h
      09.02.2022 15:44
      +3

      А в первом [[nodiscard]].


      1. amarao
        09.02.2022 15:52
        +2

        О, оно тоже есть? Я чувствую, что Rust - это C++ с человеколюбивым синтаксисом. Хотя ownership всё-таки силён...


        1. vt4a2h
          09.02.2022 16:05

          Насчёт того, насколько синтаксис Rust "человеколюбивый" у меня есть свои соображения :) Хотя, привыкнуть можно и к его особенностям. Я лично нахожу Rust (и его экосистему в целом) во многих аспектах намного более удобным чем "современный C++".


          1. amarao
            09.02.2022 16:10
            +1

            Человеколюбивость Rust'а заключается не в особой прелестности написанного, а в том, что написанное, либо соответствует задуманному, либо вызывает ошибку компиляции. Строг, но человеколюбив. Я вот в треде ниже обнаружил, что string_view по-умолчанию допускает модификацию. Во-первых это не очевидно из сигнатуры функции, во-вторых не вызывает ошибок при компиляции, если я не ожидаю, что функция to_int будет модифицировать мою строку.


            1. domix32
              09.02.2022 18:41
              -1

              что string_view по-умолчанию допускает модификацию

              Ещё и крашится на .size() в имеющихся имплементациях, если ему скормили nullptr. Хотя казалось бы, что мешало вернуть 0.


              1. ncwca
                09.02.2022 19:12
                +1

                Потому что с чего оно должно возвращать 0, если ноль - это пустая строка?


    1. myxo
      09.02.2022 15:58

      Вот так ещё больше ????

      auto to_int(std::string_view str) -> std::expected<int, std::errc> {

      fn to_int(inp: &str) -> Result<i32, err:ErrType> {


      1. amarao
        09.02.2022 16:03
        -1

        А вот тут начинаются нюансы. У Rust'а ясно написано, что inp - это немодифицируемый slice. А вот в C++ я аж полез читать - и да, string_view - хоть и слайс, но изменяемый. Ой.


        1. allcreater
          09.02.2022 16:11
          +2

          std::string_view ни при каких условиях не позволяет изменять строку, на которую ссылается, единственное, что может меняться - указатель на начало и длину при вызове методов вроде remove_prefix. Но и это можно запретить, объявив его как const.

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


        1. eao197
          09.02.2022 16:12

          string_view - хоть и слайс, но изменяемый

          В каком смысле он изменяемый? В том, что содержимое имеющегося у вас string_view может изменить кто-то снаружи?


          1. amarao
            09.02.2022 16:28
            -1

            Видимо, я плохо прочитал. Но вот ваше замечание мне напомнило, что если мы сделали slice на память и кому-то отдали, то мы всё ещё можем с переменной (для которой slice) творить что попало. Правило исключительного доступа для mut в C++ нету же...


            1. eao197
              09.02.2022 16:32
              +1

              Тут работает обычное правило C++: const view не гарантирует иммутабельности того, на что этот самый const view был получен. std::string_view -- это просто одна из разновидностей того самого const view.


              1. amarao
                09.02.2022 16:45

                И вот тут-то вот Rust оказывается чуть-чуть более человеколюбивой ситуации, потому что "кто что модифицирует" явно энфорсится компилятором.


                1. eao197
                  09.02.2022 16:52
                  +5

                  Мне не очень нравятся сравнения "а у вас негров линчуют" "а вот в этом языке вот так". Если есть возможность писать на Rust, то не суть важно, как оно в C++. Если же нужно писать на C++, то не суть важно, как оно в Rust.

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


                1. ncwca
                  09.02.2022 17:34
                  -2

                  Нет, просто раст куда более ограничен. От этого там существует тысячи костылей, где никакой компилятор ничего не энфорсит, кроме обёрток над ансейф-костылями.

                  sv - это какая-то часть строки. Этих частей много. С чего вдруг это должно "энфорсить" иммутабельность на исходную строку? Ни с чего.

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

                  А почему там что-то "энфорсится" - потому что это максимально примитивная реализация. Более примитивного ничего придумать невозможно. И причина этого не в том, что это какое-то "человеколюбие" - как раз таки всё наоборот. Его там нет. На человека там сброшена задча мучится с этими костылями.

                  Используется подобная максимально примитивная схема потому, что она элементарно реализуется, а возможности реализовать что-то больше не было. Да и нет.

                  Такая же ситуация с -> и остуствием вывода типа возврата. Просто не смогли, а все рассуждения "чтобы видеть типы" - это сказки для бедных и оправдания. Почему же тогда у лямбды есть вывод типов?

                  И сказки про "лямбда это лямбда" - такие же сказки, потому как вывод типов в лямбде есть потому, что костылём эта лямбда просто воспринимается как кусок кода. Т.е. она не-полиморфна.

                  Поэтому, даже если принять оправдание "лямбда это лямбда", то почему же лямбда не полноценно? Почему я не могу написать `let id = |x| x; id(10); id(10.);`


                  1. amarao
                    09.02.2022 18:23
                    +2

                    Вы немного неправильно понимаете ownership в Rust. Иммутабельность всего в Rust - это дефолт. Вы написали let x: u32 = 4, и x - не мутабельное. Пока вы явно не скажите mut. Поскольку программисты - существа ленивые, они не будут писать mut пока он им не потребуется. Благодаря этому у вас в коде будет минимальное количество mut'ов.

                    А ещё mut по-умолчанию эксклюзивный. Работать с объектом, который "ёщё где-то меняется" очень сложно, настолько сложно, что редкая птица долетит до середины списка CVE. Если кто-то меняет объект, до момента окончания изменений никто с ним работать не может, и, наоборот, если кто-то объект читает, никто в него писать не может. Это энфорсится бесплатно. Но это дефолт. Если вы такой умный буратина, то вы можете взять Atomic и написать код с шаренным доступом к памяти. loom вам даже может подсунуть херни в рамках выбранной вами модели памяти, и вы сможете оценить разницу между Relaxed и SeqCon.

                    Насчёт сигнатур. Вы же сами сказали, что в лямбдах прекрасно умеют выводить сигнатуры. А для функций умеют - но не будут, потому что вы правильно написали - сигнатуры, они для человеков, а не для компиляторов (хотя компиляторы в них тоже подглядывают).

                    Ваш последний пример... Во что он должен скомпилироваться для id(1u8) и для id(1.0f64)? Код-то разный. А полиморфизм должен явно задаваться, потому что если у вас компилятор за вас будет подсовывать полиморфизм там, где вы не ожидаете, то у вас опять получится как Си только с полиморфизмом. "Надо было думать что пишешь".


                    1. ncwca
                      09.02.2022 19:21
                      -5

                      Вы немного неправильно понимаете ownership в Rust. Иммутабельность всего в Rust - это дефолт. Вы написали let x: u32 = 4, и x - не мутабельное. Пока вы явно не скажите mut. Поскольку программисты - существа ленивые, они не будут писать mut пока он им не потребуется. Благодаря этому у вас в коде будет минимальное количество mut'ов.

                      К чему эта мантра? Как она связана с тем, что писал я?

                      А ещё mut по-умолчанию эксклюзивный. Работать с объектом,
                      который "ёщё где-то меняется" очень сложно, настолько сложно, что редкая
                      птица долетит до середины списка CVE.

                      К чему эти мантры? Никакого "не-умолчания нет" и к чему эта клоуна с попыткой делать вид, что я чего-то не понимаю и мне что-то объясняют? Я знаю как это работает.

                      Если кто-то меняет объект, до
                      момента окончания изменений никто с ним работать не может, и, наоборот,
                      если кто-то объект читает, никто в него писать не может.

                      Зачем, опять же, эта нелепая попытка мне что-то объяснять, когда а) я это знаю, б) я об этом сообщил выше?

                      Да и никакого "момента изменения" нет. Это всё костыли накостыленные ансейф-хаками и обёрнутые во всякие фокусы. Какое отношение это имеет к делу?

                      Это энфорсится
                      бесплатно.

                      Враньё. Никакого бесплатно нет, есть тысячи костылей с ручной проставкой лафтаймов и тысячей ансейфов даже в примитивной stdlib. Не говоря о том, что лайфатаймы дырявые и будут дырявыми всегда. Пример тот же фейкстатик.

                      Сейчас мы услышил типичные опрадвания, что дыры не дыры, баги не баги.

                      Но это дефолт. Если вы такой умный буратина, то вы можете
                      взять Atomic и написать код с шаренным доступом к памяти. loom вам даже
                      может подсунуть херни в рамках выбранной вами модели памяти, и вы
                      сможете оценить разницу между Relaxed и SeqCon.

                      Атомики на расте не выразимы. Это ансейф-хаки, которые не может работать нормально и не работают. К тому же, зачем мне брать атомики, если мне ненужны атомики?

                      К тому же какие модели памяти и прочие куллстори, если в расте нет никакой модели памяти - это набор костылей поверех си/ллвм-моделей. Что я там могу узнать?


                      1. amarao
                        10.02.2022 11:29
                        +3

                        Вы несколько раз выразили несогласие с unsafe. В чём проблема с unsafe? В целом, в рамках модели rust'а, весь C++ - это один большой unsafe. А в Rust'е сделали так, что его может быть меньше.

                        unsafe - это не хак, это метод аннотации кода, требующего внимания при review и написании. Вместо того, чтобы требовать повышенного внимания к cpp файлам в целом, можно концентрироваться только на unsafe фрагментах, именно там "умные буратины" показывают как можно делать странное так, чтобы не было больно.

                        А вы почему-то считаете, что если unsafe, то это духовный провал Rust'а.


                      1. ncwca
                        11.02.2022 22:30
                        -1

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


                    1. ncwca
                      09.02.2022 19:35
                      -4

                      Насчёт сигнатур. Вы же сами сказали, что в лямбдах прекрасно умеют
                      выводить сигнатуры. А для функций умеют - но не будут, потому что вы
                      правильно написали - сигнатуры, они для человеков, а не для компиляторов
                      (хотя компиляторы в них тоже подглядывают).

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

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

                      Бредни про "для человеком" мне даже комментировать лень. Потому что сигнатуры в расте сделаны именно что для компилятора, потому что вывода типов нет, полиморфиная модель убогая и прочее. Поэтому все эти костыли пишутся руками и уж никаким образом не для человека.

                      И, опять же, в данном случае пропаганда нам не сообщет о том - почему вдруг в лямбде сигнатура ненужна, а в функции нужна.

                      Ваш последний пример... Во что он должен скомпилироваться для id(1u8) и для id(1.0f64)?
                      Код-то разный. А полиморфизм должен явно задаваться, потому что если у
                      вас компилятор за вас будет подсовывать полиморфизм там, где вы не
                      ожидаете, то у вас опять получится как Си только с полиморфизмом. "Надо
                      было думать что пишешь".

                      Чего? Какие-то совсем жидкие оправдания. Лямбда так же может быть полиморфна, если она находится в другом контексте. И никаким образом явно это не задаётся.

                      Да и я могу просто передать в лямбду &dyn trash и всё там будет вызываться.

                      Поэтому все эти разговоры - оправдания, поэтому они такие дырявые. Если нужно явно, то почему void проставляется неявно? Либо лайфтаймы? А почему async-костыли на 99% состоят из неявно и там в сигнатурах совершенно не то, что в реальности? Почему into и прочее - это уже не плохо и не "неявно"?

                      Ах да - это другое. Всё что не можем - то неянво плохое. А как только получается родить какой костыль, то неявно уже не проблема.


                  1. ncwca
                    09.02.2022 19:43
                    -5

                    Уже группая поддержки подключилась и гадят. Прибежал проповедовать. Все ответы - пустые лозунги и игнорирование доводов оппонента. Ещё у них там на всех разум коллективный, поэтому любое "фи" в адрес пропагандиста, либо обожаемой им скриптухи - сразу набегают и гадят.

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

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

                    Так, уже группая поддержки, которую пропагандисты собирают по всяким чатам, начинает гадить в карму. Фиксирую. На начала моих ответов было -3/4.

                    Сейчас начнутся сказки, что они минусуют меня за то, что называю их пропагандистами. Придут всякие "я случайно проходит"-персонажи.

                    Фиксирую сразу. Гадить начали с первого же поста, в том числе в карму. Пропагандисты были уже после.

                    Фиксирую набег какого-то бота. Нагадил в карму и минуснул все комменты, которые были на тот момент написаны. В том числе и коммент:

                    Это обёртка над тем, что уже тысячи лет в нормальных компиляторах, а именно __builtin_unreachable

                    Этот, т.е. здесь попросту нет ничего за что минусовать. Но боту плохую подготовку получил и ещё не научился минусовать без такого явного палева.


        1. crackedmind
          09.02.2022 16:15
          +1

          The class template basic_string_view describes an object that can refer to a constant contiguous sequence of char-like objects with the first element of the sequence at position zero.
          Note: iterator and const_iterator are the same type because string views are views into constant character sequences.


          1. amarao
            09.02.2022 16:29

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


      1. ncwca
        09.02.2022 17:50
        -4

        Не больше. fn в отличии от auto в цпп - это костыль, который обусловлен слабостью "парсера". -> в цпп имеет смысла, когда как в расте - это просто костыль, потоу как лево всегда занято костылём ввиде fn/let и прочего.

        Право используется потому, потому как это даёт возможность использовать парметры как часть типа. Допустим `(auto x) -> decltype(x.err)`

        Поэтому, допустим, сущуествует template<>. Оно нужно для того, чтобы можно было определить теплейт-параметр до типа возврата. `T <T>f` - такое написать нельзя. Более-менее смышлёные последователи права ссылаются на то, что право у них по этой причине. Нет. Право там именно потому, что fn.

        Про fn - это пошло ещё с паскаля, как пример максимально примитивного парсинга. Суть там простая. У нас есть описание неких грамматических правил и нам нужно узнать то, какому правилу соответствует набор токенов, в простом случае.

        Вот самый просто способ - это максимально сильно упрощать грамматику, уменьшая коллизии в правилах. А когда от них уйти нельзя - просто тупо писать идентификатор правила слева.

        Т.е. все эти fn/let и прочее - это синтаксический мусор, который не имеет никакого смысла, кроме как для упрощения разбора. Упрощение разбора никогда актуальным не являлось. Поэтому все сказки "это для оптимизации" - являются чушью. Достаточно посмотреть на время компиляции раста. Это экономия на спичках, которая крайне сомнительна.

        Подобный подход - удел студентов, которые только начинают писать языки.

        Сейчас очень часто можно видеть использование auto -> в цпп. Это просто пропагандисткий причём призваный сместить внимание с отстутствия вывода типа возврата в расте. Потому как писать подобным образом смысла не имеет, а когда имеет - аналога в расте существовать не может в силу его скудных возможностей.


  1. tsilia
    09.02.2022 17:19

    Скажите, пожалуйста, как поживают метаклассы Герба Саттера?


    1. antoshkka Автор
      09.02.2022 17:44
      +2

      Они базируются на рефлексии, а рефлексия окажется в лучшем случае в C++26. Так что пока ожидаем


  1. domix32
    09.02.2022 18:30

    v | std::views::chunk(2); // {['n', 'o'], ['p', 'p']}
    v | std::views::slide(2); // {['n', 'o'], ['o', 'p'], ['p', 'p']}

    А оно в таком виде будет модифицировать входные контейнеры разве? Я думал range-алгоритмы ленивые.


    1. antoshkka Автор
      09.02.2022 20:04

      Да, ranges ленивые и я походу тоже: в коменте справа я написал, что мы получим если пройдёмся по всем элементам диапазона и сохраним их куда-нибудь.


  1. IGR2014
    09.02.2022 19:05

    Constexpr math - спасибо что в этом столетии! Главное, чтоб из-за обратной совместимости нам не замутили std::math::cos в дополнение к существующему std::cos, например...


    1. antoshkka Автор
      09.02.2022 20:06

      Не, вроде такое не планируется :)

      Теперь можно получится продвинуть бумагу на constexpr для <cstring>. А то как-то неправильно писать std::string_view{s}.size() вместо std::strlen(s)


  1. ncwca
    09.02.2022 21:07

    Напишу просто предложение, которое поможет многим людям. Да и реализуется оно достаточно просто. Сейчам мы можем передавать в asm только литералы строковые. Передать же туда constexpr-строку мы не можем. Нужно расширить asm, чтобы он мог принимать constexpr-строки.

    Тогда можно будет писать кодогенерацию в комплейтайме напрямую.


    1. antoshkka Автор
      09.02.2022 21:55
      +1

      Боюсь что придётся вначале стандартизировать asm: http://eel.is/c++draft/dcl.asm


  1. kovserg
    10.02.2022 11:36

    Не планируется что-нибудь для управления ограничениями на нововведения и вообще на фичи, коих всё больше и больше.
    #pragma require список требований к компилятору
    Наример
    #pragma requie c++20
    #pragma forbid raw_pointer
    #pragma forbid fpu

    Что бы если фича не запрошена или явно запрещена, что бы она останавливала компиляцию, даже если она поддерживается.


    1. mapron
      11.02.2022 07:44

      ограничениями на нововведения

      ну оно есть, компилируйте себе спокойно код с -std=c++98, никакая новая фича не проскочит.
      А если вы хотите фишечки по одной отключать в одной TU, сойдут с ума все — и разработчики компилятора, и разработчики библиотек, это поддерживать нереально, там не просто комбинаторный взрыв а атомная бомба получится.


    1. myxo
      11.02.2022 12:18

      С хедерами это крайне сложно сделать. С модулями уже попроще, есть даже предложение насчет «эпох». www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1881r0.html

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