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

image

Главные новости:

  • Расширению Concepts быть в C++20!
  • Ranges, Networking и Coroutines/сопрограммы: выпущены в эксперимент в виде TS.
  • Модули: черновик TS готов.

Что всё это значит, как это упростит написание кода и что было ещё — читайте под катом.

Concepts


Замечательная вещь под названием Concepts внесена в черновик будущего стандарта С++20. Это большая радость для разработчиков обобщенных библиотек, использующих идиому SFINAE.

Мотивирующий пример для любителей SFINAE
В вашей библиотеке есть функции `*_fast` и `*_slow`, принимающие на вход два шаблонных параметра `v` и `data`:

  1. `*_fast` — сильно соптимизированы, но требуют, чтобы следующие операции возвращали T& и были валидны:

        v += data;
        v -= data;
        v *= data;
        v /= data;
    
  2. `*_slow` — медленные, но работают со всеми типами данных.

Задача — написать функции `*_optimal`, которые используют версию `*_fast`, если это возможно:

#include <iostream>

template <class Container, class Data>
void compute_vector_fast(Container& v, const Data& data) {
    std::cout << "fast\n";
    // ...
}

template <class Container, class Data>
void compute_vector_slow(Container& v, const Data& data) {
    std::cout << "slow\n";
    // ...
}

template <class Container, class Data>
void compute_vector_optimal(Container& v, const Data& data) {
    // ??? call `compute_vector_slow(v, data)` or `compute_vector_fast(v, data)` ???
}

Без концептов эта задача, например, решается через `std::enable_if_t` и множество нечитаемого шаблонного кода.

С концептами всё намного проще:

#include <iostream>

template <class T, class Data>
concept bool VectorOperations = requires(T& v, const Data& data) {
    { v += data } -> T&;
    { v -= data } -> T&;
    { v *= data } -> T&;
    { v /= data } -> T&;
};

template <class Container, class Data>
    requires VectorOperations<Container, Data>
void compute_vector_optimal(Container& v, const Data& data) {
    std::cout << "fast\n";
}

template <class Container, class Data>
void compute_vector_optimal(Container& v, const Data& data) {
    std::cout << "slow\n";
}


Концепты позволяют:

  • писать более простой шаблонный код,
  • выдавать более короткие сообщения об ошибках при использовании неверных шаблонных параметров (в теории, пока что это не так!).

С концептами уже можно поэкспериментировать в GCC, если использовать флаг -fconcepts, например, тут. Вот последний доступный proposal на Concepts.

Ranges TS


Ranges увидят свет в виде технической спецификации. Это значит, что поэкспериментировать с ними можно будет еще до C++20.

С Ranges можно писать `sort(container)` вместо `sort(container.begin(), container.end())`, нужно только заиспользовать нужный namespace.

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

#include <vector>
#include <experimantal/ranges/algorithm>
namespace ranges = std::experimental::ranges;

int main () {
    // Функция get_some_values_and_delimiter() фозвращает вектор,
    // в котором гарантированно есть число 42
    std::vector<int> v2 = get_some_values_and_delimiter();

    // Необходимо найти число 42 и отсортировать все элементы, идущие после него:
    auto it = ranges::find(v.begin(), ranges::unreachable{}, 42);
    ranges::sort(++it, v.end());
}

Нечто подобное Александреску делал для получения супербыстрого поиска.

Любителям SFINAE и обобщённых библиотек Ranges тоже принесут счастье, так как они определяют огромное количество концептов: Sortable, Movable, Copyable, DefaultConstructible, Same…

Можно поэкспериментировать, скачав библиотеку отсюда. Вот последний доступный черновик Ranges.

Networking TS


Все, что необходимо для работы с сокетами (в том числе для асинхронной работы), будет выпущено в эксперимент еще до C++20. В основе Networking TS лежит доработанный и улучшенный ASIO.

Вот пара приятных различий:

  • В Networking TS можно передавать move-only callback. В ASIO для этого надо было на свой страх и риск поплясать с бубном макросом BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS. Так что если у вас есть функциональный объект с unique_ptr, то его можно спокойно использовать для callback.
  • Больше constexpr для базовых типов (например, для ip::address).
  • Вменяемые способы передачи аллокаторов: можно в класс-callback добавить allocator_type и метод allocator_type get_allocator(); можно специализировать шаблон associated_allocator и описать, какие методы класса надо дергать вместо get_allocator().

Можно поэкспериментировать, скачав библиотеку отсюда. Вот последний доступный черновик Networking.

Coroutines TS


Сопрограммы — это «возможность сохранить текущий стек, переключиться на другой стек и поработать там, а потом вернуться». В основном они используются для создания генераторов и асинхронной работы.
Уточнение от @masterspline
На самом деле, в стандарт вошла версия от MS, которая stackless. Она никакие стеки не переключает. По сути вошедшая в стандарт версия корутин — это функтор (функциональный объект C++, типа лямбды), который создается компилятором из функции, помеченной как «корутина». Свое состояние stackless корутина, как и функтор, держат в членах класса, а для реализации возможности многократного вызова функции-корутины, определен operatop()(), реализованный в виде конечного автомата типа Duff's device в начале которого идет switch() по текущему состоянию конечного автомата.

Самый смак получается, если смешать Coroutines TS и Networking TS. Тогда вместо асинхронного нечитабельного кода на +100 строк можно получить то же самое, но на 40 строк:

#include <ctime>
#include <iostream>
#include <string>
#include <experimental/net>

using net = std::experimental::net;
using net::ip::tcp;

std::string make_daytime_string() {
    using namespace std; // For time_t, time and ctime;
    time_t now = time(0);
    return ctime(&now);
}

void start_accept(net::io_context& io_service) {
    tcp::acceptor acceptor{io_service, tcp::endpoint(tcp::v4(), 13)};

    while (1) {
        tcp::socket socket(acceptor.get_io_service());
        auto error = co_await acceptor.async_accept(socket, net::co_future);
        if (error) break;

        std::string message = make_daytime_string();
        auto& [error, bytes] = co_await async_write(
            socket, net::buffer(message), net::co_future
        );
        if (error) break;
    }
}

int main() {
    net::io_context io_service;
    io_service.post([&io_service](){
        try {
            start_accept(io_service);
        } catch (const std::exception& e) {
            std::cerr << e.what() << std::endl;
        }
    });

    io_service.run();
}

Но вот плохие новости: такую интеграцию Coroutines TS и Networking TS в стандарт еще не привнесли. Пока что придется реализовывать ее самим.

С сопрограммами уже можно поэкспериментировать в CLANG-6.0, если использовать флаги -stdlib=libc++ -fcoroutines-ts, например, тут. Вот последний доступный черновик Coroutines.

Модули


Подготовлен черновик TS. Дело сдвинулось и есть шансы увидеть модули уже в течение года!

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

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

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

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

И наконец, финальная стадия сборки проекта — линковка. В данный момент линковщик может тратить много времени на выкидывание одинаковых блоков скомпилированного кода (вы написали функцию inline/force_inline, 100 раз её использовали, а компилятор решил её не встраивать — линкер выкинет 99 скомпилированных тел вашей функции и оставит одно). С модулями такого происходить не должно, поскольку файл модуля не будет «вкомпиливаться» внутрь собранного файла cpp.

Модули в черновике не экспортируют макросы, поэтому будет сложновато использовать их для системных файлов с множеством макросов (`<windows.h>`, я на тебя намекаю!) и поддерживать код, использующий модуль и его старый заголовочный файл (если у вас std::string описан в модуле и в заголовочном файле , то при подключении модуля и заголовочного файла будет multiple definitions, поскольку макрос для include guards не экспортируется из модуля). Это как раз такие модули, за которые вы проголосовали в прошлом посте (ваши голоса мы донесли до комитета).

Вот последний доступный черновик Modules.

Мелочи, принятые в C++20


В C++20 можно будет инициализировать bitfields в описании класса:

struct S {
    unsigned x1:8 = 42;
    unsigned x2:8 { 42 };
};

Можно будет понимать платформы endianness стандартными методами:

if constexpr (std::endian::native == std::endian::big) {
    // big endian
} else if constexpr (std::endian::native == std::endian::little) {
    // little endian
} else {
    // mixed endian
}

Можно будет инициализировать поля структур, прям как в чистом C:

struct foo { int a; int b; int c; };
foo b{.a = 1, .b = 2};

У лямбд можно будет явно указывать шаблонные параметры:

auto bar = []<class... Args>(Args&&... args) {
    return foo(std::forward<Args>(args)...);
};

Заслуги РГ21


На встречу в Торонто мы ездили с несколькими предложениями:

  • P0652R0 — конкурентные ассоциативные контейнеры. Комитет хорошо встретил предложение, посоветовал провести эксперименты для улучшения ряда мест, посоветовал улучшения в интерфейсе. Начали работу над следующей версией предложения.
  • P0539R1 — integers, размер (количество байт) которых задаётся на этапе компиляции. Возникли споры по поводу интерфейса (указывать шаблонным параметром биты, байты или машинные слова), так что в следующей итерации необходимо будет привести плюсы и минусы различных подходов.
  • P0639R0 — наше предложение направить усилия в сторону разработки `constexpr_allocator` вместо `constexpr_string + constexpr_vector`. Встретили крайне благосклонно, проголосовали за. Следующие наши шаги — прорабатывать тему вместе с Давидом.
  • P0415R0 — constexpr для std::complex. Предложение было одобрено и теперь находится в подгруппе LWG (вместе с предложением на constexpr для стандартных алгоритмов). Должно быть в скором времени смержено в черновик C++20.

    Зачем вообще эти constexpr?
    В комитете С++ активно работают над идеями рефлексии и метаклассов. Обе эти идеи требуют хорошей поддержки constexpr-вычислений от стандартной библиотеки, так что предложения на добавление constexpr — это в основном задел на будущее, чтобы при принятии в стандарт рефлексии можно было использовать стандартные классы и функции.

    Кроме того, ряду библиотек уже нужны constexpr-функции: [1], [2].

Вдобавок нас попросили представить комитету два предложения, непосредственно над написанием которых мы не работали:

  • P0457R0 — starts_with и ends_with для строк. Комитет предложил сделать это в виде свободных функций. Один из присутствующих сказал, что у них в компании есть эти методы и их используют чаще, чем остальные алгоритмы вместе взятые. Все с нетерпение ждут новой версии proposal, уже со свободными функциями.
  • P0458R0 — функция contains(key) member для классов [unordered_]map/set/multimap/multiset. Комитету идия пришлась по душе, почти отправили в LWG для внедрения в C++20.

На подходе


Обсуждали предложение по форматированию текста, и многим понравились предлагаемые возможности (вероятно, потому, что людям нравится Python):

fmt::format("The answer is {}", 42);

Обсуждали ring_span, который по функциональности напоминает boost::circular_buffer, но не владеет элементами (является view над контейнером).

На подходе битовые операции. Когда их примут, правильным ответом на вопрос «Как подсчитать количество выставленых битов в переменной X?» на собеседованиях станет «std::popcount(X)».

Планы и прочее


РГ21 планирует в ближайшее время написать предложения на std::stacktrace (в качестве прототипа послужит Boost.Stacktrace), доработать предложение на std::shared_library и на экспорт символов из динамических библиотек.

Если у вас есть идеи для C++20, если вы нашли проблемы в C++17/14/11 либо просто хотите подстегнуть разработку той или иной фичи C++ — заходите на сайт рабочей группы stdcpp.ru. Добро пожаловать!

Есть желание помочь с написанием предложений и внести своё имя в историю? Мы подготовили мини-инструкцию по написанию предложений.

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


  1. alan008
    28.09.2017 23:21
    +4

    На ней люди (в основном)

    То есть там еще и рептилоиды присутствовали?


  1. gridem
    28.09.2017 23:30
    +3

    Очень интересно, буду ждать с++20.


    Только возник вопрос с сопрограммами. Разве не должна функция start_accept иметь такое определение:


    future_t<void> start_accept(net::io_context& io_service);


    1. firk
      29.09.2017 05:36
      -5

      Очень интересно, буду ждать с++20.

      Простыню текста или компилятор который её реализует? Если второе — то как он будет называться?


  1. devalone
    28.09.2017 23:54
    +2

    Ура, модули!


  1. Chaos_Optima
    29.09.2017 00:21
    +9

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


    1. neit_kas
      29.09.2017 03:01
      +1

      Да. Собственно, м.б. кто поделится, как там с ней дела обстоят? Немного правда здесь смотрел:
      http://jackieokay.com/2017/04/13/reflection1.html#the-road-to-standardization-reflexpr-and-operator
      но статья ещё апрельская.

      Кстати, вроде ещё про транзактное программирование заикались.


  1. reversecode
    29.09.2017 01:30
    +1

    Networking TS ужасен, понимаю, для начала и так сойдет, со временем возможно его улучшат

    предлагаю компании яндекс, открыть код MultiFuture/MultiPromise итд из доклада www.youtube.com/watch?v=cEbGlHNcIl4
    и добавить его в стандарт С++20

    Неблокирующий future/promise намного больше интересен чем Networking TS и Coroutines TS


    1. antoshkka Автор
      29.09.2017 12:08

      С этим сейчас экспериментирют несколько людей из комитета. Так что обязательно добавят, но не в ближайшее время.


      1. reversecode
        29.09.2017 12:12

        а есть черновые наброски экспериментов в реализации что бы посмотреть пощупать?


        1. antoshkka Автор
          29.09.2017 12:41

          1. reversecode
            29.09.2017 12:52

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


    1. kibergus
      29.09.2017 15:37

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


      1. reversecode
        29.09.2017 17:08

        есть ссылка на гитхаб ?))


        1. kibergus
          29.09.2017 18:50

          Нет, есть опыт их использования и портирования boost::corutine под UWP. Писать код с их использованием действительно удобно. Но требуется некоторое привыкание, что некоторые вещи можно сделать очень просто и что использование mutex и иных механизмов блокировки — это антипаттерн. Код становится похож на академический ООП с передачей сообщений.


          1. reversecode
            29.09.2017 19:51

            Я не понял, вы входили в команду яндекса где их использовали или портировали для себя похожий функционал?

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


  1. Petrenuk
    29.09.2017 01:37
    -1

    А сейчас уже можно прочитать/записать файл имея что-то вроде std::wstring или std::filesystem::path? Насколько я знаю, в C++14 так и не было конструктора, скажем, std::ofstream от wstring или wchar*, а это означает что нет нормального кроссплатформенного способа прочитать файл, если в пути есть non-ASCII символы. Пожалуйста, скажите мне что я отстал от жизни и в C++17 или хотя бы C++20 эта проблема решена.


    1. orcy
      29.09.2017 06:07
      +1

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


      1. Petrenuk
        29.09.2017 16:40

        Не очень понятно, что это означает. Если у меня стоит русская локаль, и я хочу прочитать файл с индийскими буквами, это не сработает, так?
        Насколько мне известно, в Windows, как раз, проблема была более-менее решена, MSVC просто добавлял конструктор ofstream от wstring, а в GCC/Clang его не было. Короче, слава новым стандартам, теперь можно жить.


        1. khim
          29.09.2017 18:37
          +2

          Если у меня стоит русская локаль, и я хочу прочитать файл с индийскими буквами, это не сработает, так?
          Сработает. Более того, всё сработает даже если у вас русская локаль, а файл с индийскими буквами нужно открыть в программе, написанной 20 лет назад и об UTF-8 ничего не знающей.

          Насколько мне известно, в Windows, как раз, проблема была более-менее решена, MSVC просто добавлял конструктор ofstream от wstring, а в GCC/Clang его не было.
          Я бы скорее сказал, что на Windows эта проблема была создана — и теперь успешно разрулилась. В некотором смысла. В MacOS и Linux проблемы никогда и не было, а на Windows расширение всегда было (хоть и небыло стандартом), так что, в общем, неясно — чего мы достигли.


          1. Petrenuk
            29.09.2017 18:55

            Ок, т.е. если бы в Windows не было нестандартного конструктора, то все бы просто пользовались UTF-8, и были счастливы. А поскольку в MSVC есть ofstream(wstring), все пишут программы с его использованием, и ожидают что это будет работать в других системах. Это и есть проблема.

            А все стандартные библиотеки поддерживают UTF8 в, скажем, ofstream? Т.е. мне достаточно сделать буфер байтов который начинается с EF BB BF и все будет работать и в linux и в MacOS и в Windows?


            1. khim
              29.09.2017 19:28
              +4

              А поскольку в MSVC есть ofstream(wstring), все пишут программы с его использованием, и ожидают что это будет работать в других системах. Это и есть проблема.
              Именно.

              А все стандартные библиотеки поддерживают UTF8 в, скажем, ofstream?
              В корне неверная постановка вопроса. Не «стандартные библиотеки поддерживают UTF8», а «UTF8 поддерживает все стандартные библиотеки» — для того и сделан.

              Т.е. мне достаточно сделать буфер байтов который начинается с EF BB BF и все будет работать и в linux и в MacOS и в Windows?
              Нет. EF BB BF — это ещё одна проблема, созданная Windows.

              Для того, чтобы всё работало в MacOS, Windows, Android, ChromeOS — и вообще на подавляющем большинстве систем не нужно делать ни-че-го. Просто используйте функции, которые использовали в C 70х, а в C++ — с 80х — и всё.

              А вот если вам нужен ещё и Windows… тогда у вас проблемы…


              1. Petrenuk
                30.09.2017 13:38

                Ok, вроде понятно. Получается что всё-таки до C++20 нет нормального кроссплатформенного способа. Ибо чтобы заставить Windows интерпретировать мою строку как utf8 нужны пляски с бубном, а в linux — не нужны.


        1. orcy
          29.09.2017 20:20
          +2

          ofstream на уровне реализации откроет файл через системное API, на Windows это CreateFileA(char*,...)/CreateFileW(wchar_t*), на linux это open() из POSIX. open(char*, ...) на Linux понимает множество unicode через UTF8. То есть когда вы будете использовать на модном C++ конструктор c wstring, он скорее всего внутри себя будет преобразовать wstring->utf8 и вызывать open() с этим параметром(равносильно тому что вы раньше вызывали конструктор со string с данными UTF8). А вот библиотека на Windows скорее всего в конструкторе string использовала CreateFileA(), т.е. использовала системную локаль, а в конструкторе с wstring — CreateFileW(). (disclaimer: это по большей части мои предположения) Небольшой холиварчик про это есть на utf8everywhere.org

          Резюмируя: да, теперь будет портабельный передачи юникод путя в ofstream, однако на мой взгляд лучше было бы если бы Windows string конструкторе принимала бы UTF8 а не локальную кодировку.


          1. mayorovp
            29.09.2017 20:31
            +3

            На самом деле обе ОС принимают свою локальную кодировку. Просто на линуксе в какой-то момент кто-то сумел продавить utf-8 в качестве универсальной локальной кодировки — а на винде обратная совместимость.


          1. DistortNeo
            29.09.2017 20:49
            +1

            Насколько я помню, в Linux вообще нет такого понятия, как кодировка для имени файла. Имя файла — это просто набор байт, и ничего больше.


            1. orcy
              02.10.2017 14:10
              -2

              Видимо да.

              Интересно есть специальный смысл у разделителя, 0x2f "/". Когда он будет в любом байте, т.е. в Linux нельзя будет создать файл ? (0x22 0x2f) прочитал это здесь: unix.stackexchange.com/questions/39175/understanding-unix-file-name-encoding. Получается что используя utf8 строку как имя файла/путь можно получить не тот результат что ожидается.


              1. mayorovp
                02.10.2017 14:23
                +5

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

                В UTF-8 же символ ? кодируется как 0xe2 0x88 0xaf, и никаких проблем с его использованием в имени файла не возникает.


                1. orcy
                  03.10.2017 05:51
                  +1

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

                  Ну хорошо, но ведь остается проблема что в open() можно отправить строку которая не является валидной UTF8 строкой и в это случае файл будет создан или открыт. Получается что программа которая читает список файлов должна быть готова к тому что имя какого-нибудь из файлов не будет валидной UTF8 строкой. Так?


                  1. khim
                    03.10.2017 13:25
                    +2

                    Получается что программа которая читает список файлов должна быть готова к тому что имя какого-нибудь из файлов не будет валидной UTF8 строкой. Так?
                    Да. Но совершенно точно так же в Windows программа должна быть готова к тому, что имя файла не будет валидной UTF-16 строкой.

                    В обоих случаях это — проблемы GUI, ядро такие «мелочи» не интересует…


              1. khim
                02.10.2017 14:50
                +2

                Вы что-то не то вычитали. Как я уже писал: Не «стандартные библиотеки поддерживают UTF8», а «UTF8 поддерживает все стандартные библиотеки»

                Да, библиотеки для работы с TUI/GUI пришлось переделывать, так как правило «один байт = один символ на экране» перестало исполняться. Однако 99% кода — это не касается. Никакой ASCII vs UNICODE дихотомии, никаких «legacy» и «modern» программ, никаких изменений в ядре — ничего этого не нужно. Даже подстроки в регулярных выражениях можно в UTF-8 искать старыми функциями (если upcase/lowercase конвертация не нужна).

                Несколько обидно видеть этот костыль в стандарте в 2020м году — примерно как раз когда можно будет уже наконец со спокойной душой заявлять «наше приложение работает на большинстве распространённых платформ… кроме Windows… и не планируем».

                Вот в 2003м, когда реально было неясно чем попытка Microsoft'а «удавить всех» закончится — это было бы здорово. Но в 2020м?


                1. orcy
                  03.10.2017 05:42
                  +1

                  Вы точно мне ответили? Я писал о том как open() интерпретирует имя файла на Linux (вне стандартов C/C++ и прочего). Насколько я смог понять open() действительно принимает на вход произвольные бинарные данные и различает только два служебный байта: 0x2f и nul. То есть невалидная UTF8 строка тоже может именем файла. Это то что я прочитал после ответа DistortNeo мне.


                  1. khim
                    03.10.2017 13:32
                    +1

                    Вы правильно прочитали. Проблема в том, что Windows действует примерно так же (тоже только U+002F, но и U+005C, а также, иногда, U+003A), но при этом основная проблема: можно создать и использовать невалидные (с точки зрения Unicode) имена файлов — осталась.

                    Поскольку UTF-16 не решает ни одной проблемы, а только создаёт новые — использовать его в новых программах глупо, а так как писать новые программы под Windows всё менее нужно — то странно вносить его поддержку в язык в 2020м году.


                    1. orcy
                      04.10.2017 11:01

                      Про то что UTF16 не очень удобен я не спорю, но этот подход:

                      > то странно вносить его поддержку в язык в 2020м году

                      я считаю странным. Во-первых поддержку utf16 все же включили в C++17 в конструктор ifstream/ofstream. Во-вторых все же подход в рамках идеологии С++ как я ее вижу был бы обеспечить там где возможно близость к платформе, а не игнорировать существующие реалии с высокой колокольни utf8.


                      1. khim
                        04.10.2017 14:26
                        +1

                        Во-первых поддержку utf16 все же включили в C++17 в конструктор ifstream/ofstream.
                        И, как мне кажется, это уже было ошибкой.

                        Во-вторых все же подход в рамках идеологии С++ как я ее вижу был бы обеспечить там где возможно близость к платформе, а не игнорировать существующие реалии с высокой колокольни utf8.
                        Странно вы её видите. Не напомните, пожалуйста, в какой операционка функции fopen/fclose реализованы на уровне операционной системы? Или там malloc/free/operator new/operator delete?

                        Извините, но подход C/C++ — это максимальная переносимость, а никак не «максимальная близость к платформе». Вот если бы они научились ifstream/ofstream использовать WTF-8 на Windows — это был бы нормальный C/C++ подход…


    1. aTwice
      29.09.2017 10:35
      +3

      Про это было в предыдущей статье (первая новость): habrahabr.ru/company/yandex/blog/323972

      std::ofstream(L"Теперь можно открывать файлы с юникодными именами.txt") << u8"Ура!";


  1. masterspline
    29.09.2017 01:48
    +8

    Тут спойлер
    Антон, я тебя очень ценю и как специалиста по плюсам и как человека, популяризирующего нужную информацию, и как члена комитета, — в общем в твоих постах и выступлениях мне сказать совсем нечего, зато есть чему поучиться, но тут ты не прав (и еще путаешь stackfull корутины со stackless)…


    1. masterspline
      29.09.2017 03:05

      По сути корутины, принятые в стандарт — это lambda v2.0 (лямбда + 3 служебных метода + компилятор преобразует тело функции в конечный автомат по методу Даффа, с помощью switch() или как-то еще).

      Duff's device
      Кстати, Duff's device переводится «Метод Даффа», а не как это сделано в ВиКи.


      1. MacIn
        29.09.2017 22:59

        это lambda v2.0 (лямбда + 3 служебных метода + компилятор преобразует тело функции в конечный автомат

        А можно это как-то проиллюстрировать, или есть развернутое объяснение?


        1. masterspline
          30.09.2017 01:18

          Я смотрел выступления Нишанова (его абстракцию с негативными накладными расходами, он ее много раз чатал в разных вариантах) и еще можно тут посмотреть (станет понятно, что корутина для генератора — это просто лямбда с состоянием, которую зовут много раз + обертка в виде итератора, чтобы использовать в Range-based for loop, а корутина для asyncIO — это всего лишь интерфейс для большого количества библиотечного кода, который на самом деле и выполняет ввод/вывод в собственных потоках и, скорее всего, там можно было бы обойтись обычными promise/future). В результате от корутин польза скорее в том, что компилятор совсем не линейный код делает похожим на линейный (зато становится сложнее разобраться, что на самом деле происходит).

          Понятного целостного объяснения внутреннего устройства я сам до сих пор не видел.


          1. Daffodil
            30.09.2017 09:16
            +3

            На мой взгляд причина стандартизации именно stackless, в том что stackful корутины красиво реализуются библиотечно и без поддержки от компилятора. А ручная реализация stackless это некрасивый switch с goto, как его не прячь.
            Вполне возможно что поддержку stackful во временем добавят в стандартную библиотеку.

            Интересно, можно ли будет stackless корутину сериализовать?


    1. antoshkka Автор
      29.09.2017 12:47

      Добавил ваши правки в статью. Спасибо!


  1. NeoCode
    29.09.2017 07:54
    +3

    Битовые операции.
    Кроме перечисленных в табличке rotl, rotr, popcount, countl_zero, countl_one, countr_zero и
    countr_one, есть еще такая операция как «bit reverse» — разворот бит в слове (то есть первый бит становится последним, второй — предпоследним и т.д.). В x86 ее нет, но в ARM есть операция RBIT.
    infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489h/Cihjgdid.html
    Там же есть REV, REV16 и REVSH, обращающие байты в словах (это для перехода между Big/Little endian, кстати не знаю есть ли в стандарте такое… на ум приходит только htonl, htons, ntohl и ntohs, но насколько они стандартны?). Если делать то делайте сразу все.

    Еще для битовых вращений было бы прикольно задействовать <<< и >>>, но это уже украшательства.


    1. DrSmile
      29.09.2017 18:14
      +2

      Да, разворот бит полезен для FFT. Еще для всяких Z-order нужно перемежать биты с нескольких чисел, не помешал бы аналог PDEP/PEXT из x86. Но, для начала, лучше бы стандартизовали сдвиги отрицательных целых, хотя бы для intN_t.


  1. beduin01
    29.09.2017 10:11

    >сопрограммы… сохранить текущий стек
    А где он будет сохраняться? Если программа записала что-то в регистры процессора и новая сопрограмма туда тоже что-то хочет записать чтобы выполнить вычисление, то как все это будет работать?


    1. mayorovp
      29.09.2017 10:25
      +1

      В случае boost::context — регистры процессора сохраняются в, собственно, стеке. Так же как это происходит и при переключении потоков.

      В случае сопрограмм через co_await — компилятор знает про co_await и не оставляет ничего в регистрах процессора при переключении.


      1. beduin01
        29.09.2017 10:32

        Я имею ввиду что никак не могу понять чем переключение контекста отличается от сопрограмм. Переключение контекста получается полностью дамп всех регистров делает, а у сопрограмм затрагиваются только некоторые регистры?


        1. mayorovp
          29.09.2017 10:37

          Ну, boost::context как раз переключение контекста и делает, отличие от потоков — в кооперативной многозадачности, вы явно управляете на какую задачу переключаться.

          У co_await есть более сильное ограничение — у таких сопрограмм нет своего стека, свои локальные переменные они хранят в куче.


          1. beduin01
            29.09.2017 10:40

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


            1. mayorovp
              29.09.2017 10:46
              +1

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


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


  1. saterenko
    29.09.2017 10:51
    -3

    Чем дальше, тем больше плюсы превращаются в какой-то ад…

    Тогда вместо асинхронного нечитабельного кода на +100 строк можно получить то же самое, но на 40 строк

    Уверен, что 100 строк C-ного кода будут понятее, чем приведённый пример…


    1. AxisPod
      29.09.2017 11:07
      +7

      А чего непонятного, типичная конструкция от MS — async/await. MS проталкивают давненько и достаточно один раз посмотреть, во что это превращается, так сразу становится понятно. На примере C# очень лего понять.


      1. saterenko
        29.09.2017 11:13
        +2

        Человеку, который не знаком с такими конструкциями, очень тяжело по коду понять, что он делает. У меня большой опыт программирования на разных языках, в том числе и на C/C++, но я долго втыкал в код, чтобы понять, что он делает…

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


        1. mayorovp
          29.09.2017 12:28
          +3

          Оператор co_await в первом приближении можно рассматривать как оператор который "распаковывает" future: future<T> превращается в T.


          1. saterenko
            29.09.2017 12:34

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


        1. DistortNeo
          29.09.2017 12:59
          +6

          Человеку, который не знаком с такими конструкциями, очень тяжело по коду понять, что он делает. У меня большой опыт программирования на разных языках, в том числе и на C/C++, но я долго втыкал в код, чтобы понять, что он делает…

          Простите, но это уже ваша проблема, а не проблема языка. Асинхронное программирование используется уже в большом наборе мейнстримных языков: C#, Python, JavaScript. Теперь и в С++ завезли.


          Если вам требуются усилия для его понимания — поздравляю, ваши знания немного устарели. Просто потратьте немного времени на самообучение.


    1. eao197
      29.09.2017 11:44
      +4

      Так может вы их просто напишете и покажете?


      1. saterenko
        29.09.2017 11:49
        -1

        Зачем? Откройте исходники nginx, там прекрасно всё написано. В том числе и асинхронная обоработка соединений. Код читается на одном дыхании, рекомендую…


        1. eao197
          29.09.2017 11:54
          +5

          Не у всех хватает дыхания читать простыни из «простого» сишного кода. Ну и речь не о том, а о ваших словах «Уверен, что 100 строк C-ного кода будут понятее, чем приведённый пример». Без реального сравнения непонятно, откуда такая уверенность может появится у кого-то еще.


          1. saterenko
            29.09.2017 12:06
            -4

            Это же моя уверенность, да, основанная на моём опыте… Я своё мнение выссказываю и оно может не совпадать с вашим… И как я написал выше, мне пришлось долго втыкать в год, чтобы понять, что он делает… И это уже не впервый раз, когда я зависаю на современном C++ коде. Т.е. у меня есть опыт, что код C++ нередко трудно читаемый. С другой стороны, чтение кода C не вызывает у меня ни каких проблем, каким бы сложным он не был. На основании этого я и выссказал своё мнение… Это мнение, а не утверждение, что код C++ всегда и для всех сложнее в понимании, чем код C, а значит, не требует доказательств… Как-то так )))


            1. reversecode
              29.09.2017 12:10
              +8

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


              1. saterenko
                29.09.2017 12:21
                -1

                Некорректное сравнение. Вы приводите аналогию с китайским языком, подразумевая в аналогии, что он новый и сравнивая с русским, который является родным. Это по-первых. Во вторых, вы забыли указать в налогии «для меня китайский язык сложный», а я акцентировал внимание на том, что это моё мнение…

                Я на C/C++ программирую с 1997 года, т.е. уже около 20 лет… И за 25 лет опыта программирования вообще, программировал на десятке-другом разных языков… Так что не «пробовал китайский», я очень неплохо знаю китайский, но некоторые его диалекты вымораживают меня…


                1. reversecode
                  29.09.2017 12:32
                  +5

                  Так я тоже по аналогии проакцентировал на своем мнении

                  Опыт в данном случае никакой роли не играет, но я бы на вашем месте вычеркнул у себя из списка С++, вы очевидно его вообще не понимаете

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

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


                  1. saterenko
                    29.09.2017 12:47
                    -5

                    Так я тоже по аналогии проакцентировал на своем мнении

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

                    Доказательства? Возможно для вас это так, мне же знание разных языков помогает. Например, когда-то я программировал на прологе, что помогло в понимании эрланга и хаскеля.
                    Вы переходите на личности и судите меня не будучи со мной даже знакомы…
                    Возможно вы им пользуетесь как С, поэтому логика применения колбеков что С что С++ для вас легче.

                    Ну да, в статье идёт речь о будущем стандарте, в текущем описанное пока не поддерживается…
                    К чему тогда ваше личное мнение к тому что вам трудно понимать современный С++? Какие пути решения этой ситуации вы предлагаете?

                    Вам, любителю аналогий: «Погода хреновая. К чему это ваше личное мнение? Какие пути решения этой ситуации вы предлагаете?»…
                    Я предлагаю другое решение, вы возьмете книжку по С++ и освоите те моменты которые вам не понятны.

                    Умерь пыл, мальчик…


                    1. reversecode
                      29.09.2017 12:54
                      +6

                      ваши высказывание в сторону языка С++ совершенно бесполезные, не понимаете — не используйте


                    1. 0xd34df00d
                      30.09.2017 00:44
                      +1

                      Например, когда-то я программировал на прологе, что помогло в понимании эрланга и хаскеля.

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


                      1. saterenko
                        02.10.2017 09:51

                        Я бы с радостью, но хаскелем интересовался лет 5 назад. Мне язык был интересен, но стало туго со временем и я его задвинул. Поэтому тут я вам ни чем помочь не смогу. То же самое с эрлангом, которым я увлёкся где-то в начале 2000-х, и даже что-то серьёзное писал, но сейчас даже синтаксис не вспомню… Пролог был ещё раньше, где-то в 93-94 годах…

                        Языки забываешь, но концепции где-то сидят в голове и всплывают, когда видишь что-то подобное… Помниться пролог мне взорвал мозг не меньше ассемблера :)


            1. eao197
              29.09.2017 12:15
              +3

              Какой смысл был в высказывании мнения, которое вы не можете подтвердить?


              1. saterenko
                29.09.2017 12:23
                -4

                Точно такой же, как в высказываниях в статье, которые так же не подтверждаются и не доказываются… Это мнение, а не утверждение, которое требует доказательств…


                1. eao197
                  29.09.2017 12:25
                  +2

                  На самом деле в статье дана ссылка на те самые 100 строк, с которыми производится сравнение. Любой может пойти и посмотреть: www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/tutorial/tutdaytime3/src.html

                  В вашем же случае идет голословное утверждение.


                  1. saterenko
                    29.09.2017 12:30
                    -3

                    Я согласен, что по ссылке треш. Вы понимаете разницу между мнением и утверждением?

                    Вот обработка соедниений в nginx: github.com/nginx/nginx/blob/master/src/core/ngx_connection.c, куча понятного кода…


                    1. eao197
                      29.09.2017 12:39
                      +1

                      Вы понимаете разницу между мнением и утверждением?
                      Я не понимаю зачем нужно высказывать мнение, если даже автор не может его подтвердить.
                      Вот обработка соедниений в nginx:
                      Ну а пример из статьи с этой самой красотой как будет выглядеть? И вообще-то такие потроха нужно сравнивать с потрохами Asio, а не с кодом, который Asio использует.


                      1. saterenko
                        29.09.2017 12:55
                        -3

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

                        Давайте аналогию проведу. Я могу выссказать мнение «кофе — обалденный напиток», а вы его не любите и напишите «кофе горький и невкусный». Мы оба выссказали мнение об одном и том же, в обеих случаях это мнение, которое не требует доказательств, это наше личное восприятие… Как можно подтвердить, что один прав, а другой нет? Точно так же и здесь я выссказал своё мнение…


                        1. eao197
                          29.09.2017 13:00
                          +5

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

                          Но давайте попробуем на аналогии: в статье говорится, что варить кофе эспрессо быстрее и удобнее, чем варить в турке. И приводятся примеры и того, и другого. А потом приходите вы и говорите: «что-то я не понимаю, как варить кофе эспрессо, по-моему, если заваривать кофе в чайничке, то будет еще проще и быстрее». И когда вас просят продемонстрировать, как вы будете это делать, вы говорите что «это мое мнение, а вообще вон за углом в знаменитой кофейне так варят и нормально получается».


                          1. saterenko
                            29.09.2017 13:13
                            -1

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

                            Почему неверная? Зачем вы выссказываете мнение, если не можете его подтвердить?
                            Но давайте попробуем на аналогии: в статье говорится, что варить кофе эспрессо быстрее и удобнее, чем варить в турке. И приводятся примеры и того, и другого. А потом приходите вы и говорите: «что-то я не понимаю, как варить кофе эспрессо, по-моему, если заваривать кофе в чайничке, то будет еще проще и быстрее». И когда вас просят продемонстрировать, как вы будете это делать, вы говорите что «это мое мнение, а вообще вон за углом в знаменитой кофейне так варят и нормально получается».

                            Эспрессо — это сорт кофе, а не способ приготовления… )))

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


                            1. eao197
                              29.09.2017 13:16
                              +3

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


                              1. saterenko
                                29.09.2017 13:32
                                -2

                                Я привык к ровно противоположному определению: очевидно, это не то, что невозможно доказать, очевидно — это то, что тривиально можно доказать.

                                Действительно, я был неправ…
                                Очевидным является то, что бездоказательное мнение не имеет никакого веса и смысла его высказывать не было.

                                Очевидным? Где доказательства? Без доказательства вы сами себе противоречите…


                                1. 0xd34df00d
                                  30.09.2017 00:46

                                  Очевидным? Где доказательства? Без доказательства вы сами себе противоречите…

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


                                1. khim
                                  30.09.2017 02:29
                                  +4

                                  Очевидным? Где доказательства? Без доказательства вы сами себе противоречите…
                                  Ну если у вас с логикой всё настолько плохо…

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

                                  Приведение же ничем не обоснованного мнения не позволяет сделать ни того, ни другого: как-то маркировать «довод» «это ни из каких разумных посылок не следует, но я „попом чую“ — тут что-то не так» невозможно — откуда оппоненту знать, насколько у вас качественная попа? Соответственно конструктивная дискуссия после этого «довода» кончается и начинается бред.


                            1. khim
                              29.09.2017 13:24
                              +3

                              Эспрессо — это сорт кофе, а не способ приготовления… )))
                              Ну то есть о кофе у вас примерно столько же знаний, сколько о C++. Хоть бы Википедию открыли, блин: Эспре?ссо (от итал. espresso[1] ) — метод приготовления кофе путём прохождения горячей воды (около 90 °C) под давлением 8-10 бар через фильтр с молотым кофе

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

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


                              1. saterenko
                                29.09.2017 13:33
                                -2

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

                                Вот вам, любителю википедии: ru.wikipedia.org/wiki/%D0%9C%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5


                                1. DaylightIsBurning
                                  29.09.2017 13:35
                                  +3

                                  то есть у Вас есть мнение, но нет аргументов? Так и пишите тогда: «вот моё мнение, основанное чисто на эмоциях».


                                  1. saterenko
                                    29.09.2017 13:40
                                    -1

                                    то есть у Вас есть мнение, но нет аргументов? Так и пишите тогда: «вот моё мнение, основанное чисто на эмоциях».

                                    Т.е. вы всегда, когда не предоставляете аргументы, добавляете «основанное чисто на эмоциях», так? Интересный вы человек ))))


                                    1. DaylightIsBurning
                                      29.09.2017 13:43
                                      +3

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


                                      1. saterenko
                                        29.09.2017 14:09

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

                                        Как вы определяете, что место для выссказывания мнения является подходящим?

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

                                        Зачем вы со мной переписываетесь, ведь мы же, объективно, теряем время?

                                        Предлагаю закончить диспут, а то мы тут увязнем до конца дня, а мне ещё надо поработать на C/C++. Мне было приятно с вами пообщаться ;)


                                        1. DaylightIsBurning
                                          29.09.2017 15:10

                                          Как вы определяете, что ваших аргументов будет достаточно
                                          Это субъективно. Если мне кажется, что аргументы весомы можно их высказать, но если мне и самому понятно, что они недостаточно убедительны — возможно лучше воздержаться.


                                        1. 0xd34df00d
                                          30.09.2017 00:48
                                          +2

                                          ещё надо поработать на C/C++

                                          Второй раз уже за вашим авторством это С/С++ вижу, а оно мне глаз немного режет. Опыт говорит, что люди, которые так пишут, на самом деле Так вы на С или на С++ работаете?


                                          1. saterenko
                                            02.10.2017 09:45
                                            +1

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


                                          1. FlameStorm
                                            03.10.2017 12:38

                                            На C++ можно по разному писать, как и на любом другом языке.

                                            В том числе, ничего криминального нет в стиле использования C++ как «C с классами ООП, использованием стандартных библиотек и вставок на ассемблере». И это может выглядеть и работать прекрасно в опытных руках.

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


                                            1. 0xd34df00d
                                              03.10.2017 19:48
                                              +1

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


                                              1. FlameStorm
                                                03.10.2017 21:53

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


                            1. DaylightIsBurning
                              29.09.2017 13:30

                              Почему неверная? Зачем вы выссказываете мнение, если не можете его подтвердить?
                              Доказывать уместность аналогии должен тот, кто её привёл, а не наоборот. Если это затруднительно — нужно отказаться от аналогии.


                              1. saterenko
                                29.09.2017 13:37

                                Доказывать уместность аналогии должен тот, кто её привёл, а не наоборот. Если это затруднительно — нужно отказаться от аналогии.

                                Давайте подиспутируем… Вы будете что-то доказывать, а я вам, в качестве обратной связи буду говорить одно слово «Ложь». Вы будете продолжать доказывать или плюнете? Вот и тут на мою аналогию ответили только «Неверная», не написав почему…


                                1. DaylightIsBurning
                                  29.09.2017 13:42
                                  +3

                                  Вы будете что-то доказывать, а я вам, в качестве обратной связи буду говорить одно слово «Ложь»
                                  Если я приведу аргументы, а Вы ответите просто «ложь», то в глазах рационального наблюдателя, моя позиция выиграет в диспуте.
                                  Вот и тут на мою аналогию ответили только «Неверная», не написав почему
                                  Аналогия — это не аргумент. Аналогия может стать аргументом только в том случае, если обе стороны признают аналогию справедливой. Если оппонент не согласен с тем, что аналогия уместна — от аналогии необходимо либо отказаться, либо сперва убедить оппонента в её уместности. Это сложно, так как аналогию вынужден защищать тот, кто её привёл.


                                  1. saterenko
                                    29.09.2017 13:52

                                    Если я приведу аргументы, а Вы ответите просто «ложь», то в глазах рационального наблюдателя, моя позиция выиграет в диспуте.

                                    Как можно в диспуте «Погода хорошая» и «Погода плохая» выиграть? Можно только сказать, собрав статистику, что такой-то процент считает погоду хорошей, а такой-то плохой, но истины тут быть не может, потому как это мнение, а не факт.
                                    Аналогия — это не аргумент. Аналогия может стать аргументом только в том случае, если обе стороны признают аналогию справедливой. Если оппонент не согласен с тем, что аналогия уместна — от аналогии необходимо либо отказаться, либо сперва убедить оппонента в её уместности. Это сложно, так как аналогию вынужден защищать тот, кто её привёл.

                                    Согласен, аналогия — это попытка донести информацию иносказательно. Если собеседник выражает несогласие одним лишь «несогласен», как можно вести какой-либо диспут? Я вам об этом и написал, если я каждый раз буду говорить «ложь», диспут зайдёт в тупик…


                                    1. DaylightIsBurning
                                      29.09.2017 14:01
                                      +3

                                      Как можно в диспуте «Погода хорошая» и «Погода плохая» выиграть?
                                      Вообще можно, если вы на форуме метеорологов. По сути же, если бы Вы написали, что Ваше мнение о корутинах построено чисто на интуиции — его бы проигнорировали. Максимум можно было бы по голосам за и против к этому комментарию судить о том, сколько людей разделяют вашу оценку.
                                      Если собеседник выражает несогласие одним лишь «несогласен», как можно вести какой-либо диспут?
                                      Если несогласие направлено на аналогию, то диспут нужно продолжать отказавшись от аналогии или привести исчерпывающее доказательство её уместности. Это такая особенность аргументов по аналогии.


                                      1. saterenko
                                        29.09.2017 14:19

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

                                        Идёт дождь. Мне нужен дождь, чтобы земля увлажнилась, чтобы картошка лучше росла, я утверждаю «погода прекрасная». Вы хотели позагорать на солнышке и утверждаете «погода отвратительная». Кто прав? Мнения противоположные на одно и то же.
                                        По сути же, если бы Вы написали, что Ваше мнение о корутинах построено чисто на интуиции — его бы проигнорировали. Максимум можно было бы по голосам за и против к этому комментарию судить о том, сколько людей разделяют вашу оценку.

                                        Моё мнение было о читабельности современного C++ кода. К корутинам вообще отношусь прекрасно, очень интересное решение. И не думаю, что проигнорировали бы, выссказывание было весьма холиварное и молодые любители C++ наверняка его не проигнорировали бы.


                                        1. DaylightIsBurning
                                          29.09.2017 15:13
                                          +1

                                          Кто прав?
                                          Я же сразу написал, что это зависит от контекста. Контекст задаёт целевую функцию, — что такое «хорошая» и что такое «плохая». Если контекст — фермерский клуб, разговор на тему хорошей погоды может быть вполне конструктивным.


                    1. mayorovp
                      29.09.2017 13:16
                      +4

                      Вот обработка соедниений в nginx: github.com/nginx/nginx/blob/master/src/core/ngx_connection.c, куча понятного кода…

                      У вас куда-то пропала частица "не".


                      В приведенном вами файле:


                      1. куча директив условной компиляции;
                      2. местами используется вложенность управляющих конструкций в 4 и более слоев;
                      3. несколько функций не влезают в экран по высоте.

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


                      1. saterenko
                        29.09.2017 15:57
                        -1

                        1. Да, но как иначе вы определите, можете вы использовать некоторую функцию или нет? Сушествует ли опция сокета в этой версии ядра или нет? В плюсах точно так же придётся использовать директивы.
                        2. Разве в C++ как-то избавились от этого? С++ в чём-то тут отличается от C?
                        3. И? В С++ такого не бывает?

                        Это не проблемы языка, это особенности стиля программирования конкретного человека и C++ от этого тоже не застрахован.

                        Субъективно, не тяжело, а очень просто. Когда я писал свой первый большой проект на C, лет 10 назад, nginx был моим reference manual по сетевому программированию, код Игоря очень легко читается.


                        1. mayorovp
                          29.09.2017 16:22
                          +3

                          Да все бывает. Просто конкретно тот код, который вы привели в качестве эталона понятности — нихрена не понятный.


                          1. saterenko
                            29.09.2017 16:27
                            -2

                            Ну, на вкус и цвет… Я же выссказывал своё мнение, что мне понятнее… И верю, что вам код из статьи более понятен, все мы разные…


                            1. mayorovp
                              29.09.2017 16:32
                              +1

                              Да, я знаю про вкус, цвет и фломастеры. Тем не менее, мне очень хочется знать, каким образом вы определяете какой именно блок закрывает вот эта скобка:


                              Простыня кода картинкой


                              1. saterenko
                                29.09.2017 16:58
                                -3

                                Очевидно тот, который начался выше. Вы же не с конца читаете код, значит знаете, какой это блок…


                                1. mayorovp
                                  29.09.2017 17:00
                                  +5

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


                                  Более аккуратный код хорошо читается в любом направлении.


                                  1. saterenko
                                    29.09.2017 17:22

                                    Ну, я не помню, чтобы мне надо было читать код наоборот ))) Но стиль Игоря мне не очень нравится, много пустого места, я люблю более сжатый код… Хотя и бывают функции на сотни строк, типа FSM для парсинга HTTP.


                                    1. DistortNeo
                                      29.09.2017 17:30
                                      -2

                                      Каждому своё. Мне по стилю форматирования приведённая простыня кода, наоборот, нравится.

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

                                      Ну и вертикально ориентированный монитор для чтения такого кода будет очень удобен.


                              1. DistortNeo
                                29.09.2017 17:00

                                Используйте IDE с подсветкой блоков (indent guides, vertical lines, ...).


                                1. mayorovp
                                  29.09.2017 17:03
                                  +2

                                  Для этого придется сначала скачать код с гитхаба.


                                  Так-то хорошая IDE имеет бороться с распухшим кодом, с этим не спорю.


            1. Antervis
              29.09.2017 14:28
              +4

              вы сравниваете код на си, который не развивается, с кодом на с++, который развивается. Ваши знания с++ устаревают, и виноваты в этом вы.

              Уверен, что 100 строк C-ного кода будут понятее, чем приведённый пример…

              На си это будет не 100 строк, а за 400. Их и читать будет сложнее, просто в силу объема, и количество ошибок будет квадратнопропорционально выше


              1. saterenko
                29.09.2017 15:03
                -2

                вы сравниваете код на си, который не развивается, с кодом на с++, который развивается. Ваши знания с++ устаревают, и виноваты в этом вы.

                Вы оправдываете читабельнность кода C++ его развитием? Развитие, в моём понимании, должно улучшать, а не ухудшать читабельность кода… Может C и так хорош, потому и не надо его куда-либо дальше развивать.

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

                На си это будет не 100 строк, а за 400. Их и читать будет сложнее, просто в силу объема, и количество ошибок будет квадратнопропорционально выше

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

                Вот набросал примерно то же самое на C, обработка HTTP-запросов:
                #include <ev.h>
                #include "cor_http.h"
                
                void
                cor_http_server_cb(cor_http_request_t *r, void *arg)
                {
                    cor_http_response_t res;
                    cor_http_response_init(&res, r);
                    cor_http_response_set_code(&res, 200);
                    cor_http_response_set_body(&res, "answer", 6);
                    cor_http_response_send(&res);
                }
                
                int main() {
                    struct ev_loop *loop = EV_DEFAULT;
                    cor_http_t *http = cor_http_new(loop, "127.0.0.1", 8000, NULL, NULL);
                    if (!http) {
                        return 1;
                    }
                    if (cor_http_start(http, cor_http_server_cb, http) != cor_ok) {
                        cor_http_delete(http);
                        return 1;
                    }
                    ev_run(loop, 0);
                    cor_http_delete(http);
                }
                

                Что тут сложного? Где тут 400 строк и «квадратнопропорционально выше», простите, не понял, что вы этим хотели сказать…


                1. mayorovp
                  29.09.2017 15:10
                  +3

                  Вот это уже больше похоже на нормальный код.

                  Но здесь приведен тривиальный алгоритм, веселье начинается когда нужно, к примеру, в процессе обработки http-запроса сделать запрос к СУБД. Или, еще веселее, пачку запросов в цикле (да, я знаю, делать запросы к СУБД в цикле — дурной тон, но иногда надо).


                  1. saterenko
                    29.09.2017 15:33
                    -1

                    Вот тут и начинается искусство, когда надо сложные вещи «скрыть» и предоставить простой инструмент для выполнения задачи… Мне не приходилось из цикла обработки http-запросов обращаться к базе, как правило, работа с базой висит в отдельном потоке и занимается «синхронизацией» данных из демона в базу и обратно. Но, думаю, можно что-то красивое придумать и для вашей задачи. Будет немногим больше кода чем в статье, но не будет сложно для понимания…


                    1. mayorovp
                      29.09.2017 15:52
                      +3

                      Вот в том-то и дело, что где-то это искусство, а где-то для этого есть языковая поддержка.


                      1. saterenko
                        29.09.2017 16:11
                        -1

                        Рано или поздно языковой поддержки перестаёт хватать и всё равно приходится творить… И когда вам надо написать быстрое приложение, вы начинаете отказываться от STL, лямбд и другого сахара… C++ скрывает некоторые сложности по сравнению с C, но это не обходится бесплатно…


                        1. eao197
                          29.09.2017 16:22
                          +7

                          И когда вам надо написать быстрое приложение, вы начинаете отказываться от STL, лямбд и другого сахара…
                          Н-да… Поинтересуйтесь что говорят люди, которым приходится писать быстрые приложения на C++.

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


                          1. saterenko
                            29.09.2017 16:34
                            -4

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

                            Про какие вы байки?


                            1. mayorovp
                              29.09.2017 16:37
                              +5

                              Байки про отказ от STL и лямбд. Там подробно рассказывается как STL и лямбды замечательно работают в задачах HFT.


                              1. saterenko
                                29.09.2017 16:42
                                -1

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


                                1. mayorovp
                                  29.09.2017 16:43
                                  +3

                                  Язык это не скрывает, язык это пишет в документации.


                                  1. saterenko
                                    29.09.2017 17:06
                                    -1

                                    Мой опыт чтения чужого C++ кода говорит об обратном… Хотя, и на C это нередкость…


                                1. 0xd34df00d
                                  30.09.2017 00:55
                                  +2

                                  Самые вкусные места для работы (по части HFT), что я знаю, любят лямбды (они вообще никакого оверхеда сами по себе не дают, о чём вы?!), обмазываются темплейтами и констекспрами для написания эффективных и поддерживаемых парсеров биржевых данных и тыкают палочкой в Rust.


                            1. eao197
                              29.09.2017 16:37
                              +5

                              А что там говорят? По большей части банальные вещи
                              Т.е. вы не просмотрели слайдов доклада, но говорите про «банальные вещи, применимые к языку программирования»? В том числе и про использование C++ных шаблонов для получения быстрого кода?
                              Про какие вы байки?
                              Про то, что необходимо отказываться от STL для получения быстрого кода. Про лямбды — это вообще шедеврально.

                              Вы, часом, лямбды с std::function не путаете?


                              1. saterenko
                                29.09.2017 16:55
                                -3

                                Т.е. вы не просмотрели слайдов доклада, но говорите про «банальные вещи, применимые к языку программирования»? В том числе и про использование C++ных шаблонов для получения быстрого кода?

                                Вы у меня за спиной стояли и смотрели, что я делал? Зачем вы мне приписывает то, чего не знаете? Я просмотрел слайды. Но я давно программирую на C и увлекаюсь низкоуровневой оптимизацией, в том числе и на уровне ассемблера, потому для меня то, что там написано — это банально, это самое начало…

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

                                Вы меня верно поняли, я про STL писал, а не про шаблоны…


                                1. eao197
                                  29.09.2017 16:59
                                  +2

                                  Зачем вы мне приписывает то, чего не знаете?
                                  Я не приписываю, я интересуюсь. У меня вопросики стоят в надежде, что вы проясните ситуацию.
                                  Вы меня верно поняли, я про STL писал
                                  STL уже перестал быть Standard Template Library? Как давно?


                                  1. saterenko
                                    29.09.2017 17:12

                                    Я не приписываю, я интересуюсь. У меня вопросики стоят в надежде, что вы проясните ситуацию.

                                    Ну значит вы неточно выразились, потому как в вашем предложении «Т.е. вы не просмотрели слайдов доклада» является утверждением, после чего идят вопрос…

                                    STL — это контейнеры, итераторы, алгоритмы и т.п., реализованные посредством шаблонов. Т.е. я могу использовать шаблоны, но не использовать элементы STL, скажем, std::vector, std::sort, std::map и т.п.


                                1. mayorovp
                                  29.09.2017 17:02

                                  Обратите внимание: там на одном из слайдов используется класс std::unique_ptr<>. Этот класс, вообще-то, входит в STL.


                                  Значит, даже в HFT от STL не отказываются.


                                  1. saterenko
                                    29.09.2017 17:19
                                    -1

                                    Я тоже использую std::unique_ptr<> и использую другие контейнеры, но не в критичных местах и переиспользую их, если есть возможность, чтобы избежать лишних выделений памяти…


                          1. Kobalt_x
                            29.09.2017 20:30
                            -5

                            "Don't be afraid to use exceptions." И дальше можно не читать. Именно из-за exceptions не возможно нормально использовать STL при разработке дров и проч. И везде нужно писать свой "очень нужный"vector/map и проч или еще хуже писать на C и обмазываться макросней.


                        1. mayorovp
                          29.09.2017 16:26
                          +2

                          Отказ от STL не означает отказа от шаблонов (template). Отказ от лямбд и вовсе не имеет смысла — они при правильном приготовлении столь же быстрые как и обычные функции.


                          И почему вы противопоставляете языковую поддержку и творчество?


                          1. saterenko
                            29.09.2017 16:38

                            Почему отказ от STL означает отказ от шаблонов? Шаблоны мощный инструмент, я бы с удовольствием использовал их в C. Применение шаблонов не означает, что надо применять STL.

                            Не противопоставляю, я говорю о том, что язык не сделает за вас красиво, какой бы сахар там не был…


                            1. mayorovp
                              29.09.2017 16:41

                              Шаблоны — это сахар. STL — это конкретная библиотека вокруг языкового сахара.


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


                              1. saterenko
                                29.09.2017 17:05

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

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

                                Не знаю как конкретно реализован co_await, но подозреваю, что сохраняются все локальны переменные, идёт выход из функции, а потом возврат в функцию с восстановлением всех переменных. А это может создавать реальный оверхед…


                                1. alexeykuzmin0
                                  29.09.2017 17:09

                                  А это может создавать реальный оверхед
                                  И все же, корутины — это negative overhead abstraction. Они как минимум не хуже, чем все, что можно реализовать руками, а иногда лучше.


                                1. mayorovp
                                  29.09.2017 17:15
                                  +2

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


                                  С другой стороны, посмотрите какая красота получается: любая реализация FSM так или иначе сводится или к виртуальным вызовам, или к большому switch. А тут компилятор может себе позволить использовать в качестве состояния непосредственно указатель на ту инструкцию с которой следует продолжать!


                                  Руками такое можно реализовать только выключив в компиляторе всю оптимизацию.


                                  1. saterenko
                                    29.09.2017 17:31

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

                                    Т.е. потенциально это будет медленнее, чем выделение памяти на стеке…

                                    С другой стороны, посмотрите какая красота получается: любая реализация FSM так или иначе сводится или к виртуальным вызовам, или к большому switch. А тут компилятор может себе позволить использовать в качестве состояния непосредственно указатель на ту инструкцию с которой следует продолжать!

                                    Да, красиво, но на сколько это будет эффективно… Надо мерять…


                                    1. mayorovp
                                      29.09.2017 17:36
                                      +3

                                      Т.е. потенциально это будет медленнее, чем выделение памяти на стеке…

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


                                      Тем более что там можно свой аллокатор добавить.


                                    1. antoshkka Автор
                                      29.09.2017 17:43

                                      Т.е. потенциально это будет медленнее, чем выделение памяти на стеке…

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

                                      Другими словами — если компилятор вставит вызов аллокатора, то написать без динамической аллокации руками у вас не получится, без серьёзной переработки логики приложения. См изначальный пример с Boost.Asio. Там есть «new tcp_connection», так вот, этот new в примере с корутинами фактически «переехал» внутрь имплементации корутины.


                        1. alexeykuzmin0
                          29.09.2017 16:28
                          +2

                          когда вам надо написать быстрое приложение, вы начинаете отказываться от STL, лямбд и другого сахара
                          Конкретно корутины — это negative overhead abstraction


                        1. Chaos_Optima
                          30.09.2017 02:13
                          +3

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

                          Ох лол, работаю с графикой (рендеры, шейдеры, генераторы волос, рейтрейсинг и прочее для 3D мультфильмов) с появлением лямбд производительность, и скорость написания кода очень сильно выросла, а главное код стало намного легче читать. А stl как использовался так и используется ещё ни разу stl не была причиной проседания производительности, а с приходом мува код стало ещё проще писать без потерь в производительности. Вы ничего не знаете про использование новых стандартов, они сильно повышают читабильность и скорость написания кода, при этом ещё умудряются повысить производительность. Вы либо не удосужились потратить время и разобраться либо вы слепо боготворите С


                1. eao197
                  29.09.2017 15:39
                  +4

                  Вообще-то это совсем не тот код. Но раз уж вы хоть каким-то кодом на чистом C разродились, то вот его аналог на C++:

                  #include <iostream>
                  #include <restinio/all.hpp>
                  
                  int main()
                  {
                    restinio::http_server_t<> http_server{
                      restinio::create_child_io_context(1),
                      [](auto & settings) {
                        settings.port(8080).address("localhost")
                          .request_handler([](auto req) {
                            req->create_response().set_body("answer").done();
                            return restinio::request_accepted();
                          });
                      }};
                  
                    http_server.open();
                    std::cin.ignore();
                    http_server.close();
                  
                    return 0;
                  }

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


                  1. saterenko
                    29.09.2017 16:03
                    -2

                    Вы хотите сказать, что ваш код легче читается? Эта многоуровневая вложенность? Я ведь тоже могу сократить размер кода сокращением названий функций, убрать некоторые проверки и отсылать ответ вызовом одной функции… И тогда единственным выигрышем будет возможность использовать лямбды, и то, весьма сомнительный выигрыш…


                    1. eao197
                      29.09.2017 16:08
                      +8

                      Речь вовсе не про вложенность.

                      Вот у вас, например, недостаточно просто объявить cor_http_reponse_t и затем вызвать cor_http_response_set_body. Нужно еще предварительно вызвать cor_http_response_init.

                      Нельзя просто после ev_run сделать return, нужно еще предварительно вызывать cor_http_delete.

                      Нужно объявлять переменную loop со специальным значением.

                      Это все детали, которые легко упустить. А потом искать проблемы. Именно поэтому «простой» код на C получается объемнее и требует к себе большего внимания.

                      Именно поэтому вас и просили написать таки те самые 100 строк кода на C. Дабы вы сами в этом смогли убедиться.


                      1. saterenko
                        29.09.2017 16:19
                        -2

                        Да, в C нет конструкторов и деструкторов, весьма полезная штука. Но нет большой разницы между cor_http_reponse_t *res = cor_http_reponse_new(); и CorHTTPRespose res; Просто конструктор вызывается явно.

                        Переменную loop можно внести и внутрь сервера, просто я взял кусок из проекта и запостил сюда, один loop используется во множестве мест, а не только в http-сервере, в C++ так же пришлось бы его выносить в отдельную переменную…

                        Разве в C++ меньше вероятность что-то упустить? Мне кажется, в плюсах гораздо больше способов прострелить себе ногу )))


                        1. eao197
                          29.09.2017 16:24
                          +10

                          Но нет большой разницы между cor_http_reponse_t *res = cor_http_reponse_new(); и CorHTTPRespose res; Просто конструктор вызывается явно.
                          Вообще-то разница прям таки принципиальная. И заключается она не столько в конструкторах, сколько в деструкторах.


                          1. saterenko
                            29.09.2017 16:45
                            -1

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


                            1. eao197
                              29.09.2017 16:50
                              +6

                              То, что вам не надо заморачиваться удаление данных?
                              Да.
                              По моему опыту, в этом нет ни каких проблем…
                              Ну что уж тут поделать. У вас нет. А вот у огромного количества разработчиков есть.


                              1. saterenko
                                29.09.2017 17:07
                                -3

                                Ну что уж тут поделать. У вас нет. А вот у огромного количества разработчиков есть.

                                Видать я избранный, счастливчик )))))))


                              1. reversecode
                                29.09.2017 17:07
                                +7

                                у него опыт использования С++ ~25 лет, зачем вы с ним продолжаете дискуссию? он пишет на С с классами и считает что это С++, пусть дальше так считает


                                1. eao197
                                  29.09.2017 18:06

                                  Вроде бы только 20 лет (с 1997-го). 25 — это у меня :)

                                  Но после утверждения:

                                  шаблоны и STL — это разные вещи
                                  смысл продолжать дискуссию пропал.


                    1. DistortNeo
                      29.09.2017 16:14
                      +2

                      Да, лямбду я бы оформил в виде отдельной функции. Принципы SOLID и всё такое.


                      1. eao197
                        29.09.2017 16:53

                        Мне просто интересно, вот в таком выражении:

                        std::sort(std::begin(cnt), std::end(cnt),
                          [](const auto & a, const auto & b) {
                            return std::tie(a.a, a.b, a.c) < std::tie(b.a, b.b, b.c);
                          });
                        вы бы лямбду в отдельную функцию вынесли бы? Ну SOLID и все такое…


                        1. DistortNeo
                          29.09.2017 16:58
                          +1

                          Не передёргивайте. Код должен быть тестируемым.

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

                          А вот протестировать веб-сервер с лямбдой будет проблематично.


                          1. eao197
                            29.09.2017 17:04

                            Ничего сложного. Заходите браузером на localhost и видите результат. Или curl-ом из командной строки.

                            Вообще подобные претензии к примеру уровня hello_world, это внушаить.


                        1. 0xd34df00d
                          30.09.2017 01:01

                          Лично я бы написал отдельную функцию вроде comparingBy (один раз в жизни/в проекте) и передал в неё лямбду, делающую из a тупл. Перечислять один и тот же список аргументов дважды — немножко моветон и потенциально опасно, особенно если типы некоторых из них совпадают.


                          Зато помогает заработать авторам PVS, в принципе.


                          1. eao197
                            30.09.2017 09:22

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

                            std::sort(std::begin(cnt), std::end(cnt),
                              [](const auto & a, const auto & b) {
                                const auto tie = [](const auto & x) { return std::tie(x.a, x.b, x.c); };
                                return tie(a) < tie(b);
                              });

                            Ну а сам предикат для sort-а выносить в отдельную функцию имеет смысл если он повторяется в коде несколько раз (если два раза, то это уже сигнал к рефакторингу). Но тогда еще нужно посмотреть, может в отдельную функцию следует вынести не один предикат, а весь sort с этим предикатом.

                            Однако, поинт вообще был в другом.


                            1. 0xd34df00d
                              30.09.2017 19:32
                              +1

                              Сравните ваш код с


                              std::sort(std::begin(cnt), std::end(cnt),
                                  comparingBy([](const auto& x) { return std::tie(x.a, x.b, x.c); }));

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


                              1. eao197
                                30.09.2017 19:46

                                У нас в чем цель? Получить максимально компактный код? Ну так вы его получили, но ценой введения еще одной сущности — compatingBy, про которую нужно знать.

                                Выигрыш ли это? А вот не факт. Если у вас вызовов std::sort с кастомными компараторами множество, то дополнительный comparingBy может себя оправдать. Если же std::sort вызывается всего один раз, то делать еще и comparingBy — это уже поклонение паттернам вместо здравого смысла.

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


                          1. Antervis
                            30.09.2017 19:14

                            простейший вариант — реализовать operator <. Сортируйте сколько влезет


                            1. 0xd34df00d
                              30.09.2017 19:33
                              +1

                              Далеко не у всех типов есть единственным образом реализуемый operator<.


                              1. mayorovp
                                01.10.2017 11:05
                                +1

                                … и даже если таковой есть — это еще не значит что при сортировке нужен именно он


                  1. DistortNeo
                    29.09.2017 16:04
                    +3

                    Терпеть не могу K&R стиль расстановки скобок, уж простите. С ним тяжело глазами выцеплять логически разные блоки. Вот так мне сильно более приятно читать код:


                    #include <iostream>
                    #include <restinio/all.hpp>
                    
                    int main()
                    {
                      restinio::http_server_t<> http_server
                      {
                        restinio::create_child_io_context(1),
                        [](auto & settings)
                        {
                          settings
                            .port(8080)
                            .address("localhost")
                            .request_handler([](auto req)
                            {
                              req->create_response().set_body("answer").done();
                              return restinio::request_accepted();
                            });
                        }
                      };
                    
                      http_server.open();
                      std::cin.ignore();
                      http_server.close();
                    
                      return 0;
                    }


                  1. Kobalt_x
                    29.09.2017 20:40

                    «http_server.close()» а оно что не raiiшное, а то больно глаз корежит


                    1. eao197
                      30.09.2017 09:23

                      Еще не все сделано, поэтому пока так.


                1. Antervis
                  30.09.2017 19:07

                  он асинхронный?


                  1. saterenko
                    02.10.2017 09:54

                    Да, асинхронный. Вот внутренности, если интересно: github.com/saterenko/libcore/blob/master/src/cor_http.c


                    1. Antervis
                      02.10.2017 21:11
                      +1

                      Признаться, думал что нет.

                      Тем не менее, это лишь доказывает мою точку зрения:

                      На си это будет не 100 строк, а за 400. Их и читать будет сложнее, просто в силу объема, и количество ошибок будет квадратнопропорционально выше

                      Объем приведенного вами кода мал. А вот объем кода библиотеки, которую вы использовали, переваливает за 1000 строк (и это без заголовочника). В то время как в статье речь идет о функционале «из коробки». А внешняя зависимость влечет усложнение сборки/деплоя и усложняет проверку на корректность


                      1. saterenko
                        03.10.2017 10:46
                        +1

                        Объем приведенного вами кода мал. А вот объем кода библиотеки, которую вы использовали, переваливает за 1000 строк (и это без заголовочника). В то время как в статье речь идет о функционале «из коробки». А внешняя зависимость влечет усложнение сборки/деплоя и усложняет проверку на корректность

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

                        В C++ давным давно есть std:map, но существует десятки алтернатив, которые придётся подключать, если вам надо, чтобы код работал быстро…

                        В серьёзном проекте вы не обойдётесь без внешних зависимостей, так что аргумент весьма сомнительный… Да, nginx без внешних зависимостей, но единственный пример, который я знаю, Сысоев маньяк, в хорошом смысле этого слова ))


                        1. eao197
                          03.10.2017 11:13
                          +1

                          Тем не менее, даже в своей библиотеке вы вынуждены копипастить однотипные фрагменты кода и менять там всего по одной строчке (например, раз и два). Это как раз то, что более выразительные языки (вроде С++ или Rust) позволяют не делать, экономя время и силы разработчиков (и без лишних накладных расходов в run-time). Причем не столько во время написания кода, сколько во время сопровождения и развития.


                          1. saterenko
                            03.10.2017 11:30
                            -1

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


                            1. eao197
                              03.10.2017 12:21
                              +3

                              Исключения здесь вообще не при чем. Ну вот совсем. В том же C++ вы можете объявить cor_http_t как unique_ptr с кастомным deleter-ом. И тогда ни вам, ни пользователям вашего кода не придется думать, кто и когда должен освобождать значение, возвращенное cor_http_new. В самом cor_http_new вы можете использовать локальные лямбды, для того, чтобы сократить количество писанины. Что-то вроде:

                              const auto log_and_return_null = [&](const char * msg) {
                                cor_log_error(log, msg);
                                return nullptr;
                               };
                              ...
                              if(!ctx)
                                return log_error_and_return_null("can't malloc");
                              ...
                              if(!ctx->buf_pool)
                                return log_error_and_return_null("can't cor_buf_pool_new");
                              ...
                              if(!ctx->requests)
                                return log_error_and_return_null("can't cor_list_new");
                              ...

                              И писать нужно меньше, и вероятность допустить ошибку ниже, и даже думать больше не нужно. Нужно только перестать смотреть на C++ как на «C с чем-то».


                              1. saterenko
                                03.10.2017 12:42
                                -1

                                С unique_ptr согласен, так и поступаю в проектах C++. Но в голом C нет конструкторов и деструкторов, поэтому приходится вызывать деструкторы явно…

                                По поводу log_error_and_return_null, можно точно так же написать функцию на C, но выгода от этого сомнительна, в том же исходнике всего 5 мест, где используется вывод ошибки и возврат NULL. А если вам нужно warn или info вывалить, писать для них функции? А то, что cor_log_error работает с переменным набором параметров означает, что во всех этих обёртках придётся его поддерживать… Весьма сомнительно, что будет реальный выигрыш… Плюс программисту надо помнить, что у него есть набор подобных «обёрток»…


                                1. eao197
                                  03.10.2017 12:46
                                  +5

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

                                  И вот такую «простоту» вы пытаетесь противопоставить растущей сложности C++.


                                  1. saterenko
                                    03.10.2017 12:52
                                    -4

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

                                    Не язык делает код трудночитаемым, а программист…


                                    1. eao197
                                      03.10.2017 12:58
                                      +5

                                      Простота кода зависит не от языка, а от программиста.
                                      Программы на brainfuck-е смотрят на вас с недоумением.
                                      Тот же, неоднократно упоминаемы мною nginx, прекрасно читается.
                                      Это может быть следствием профдеформации.

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

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


                                      1. saterenko
                                        03.10.2017 13:12
                                        +1

                                        Программы на brainfuck-е смотрят на вас с недоумением.

                                        Вы используете brainfuck в работе?
                                        Это может быть следствием профдеформации.

                                        Можете пояснить, что конкретно вы имеете в виду?
                                        С++ позволяет стоить что угодно, хоть нормальный код, хоть ненормальный. Тогда как на C вы вынуждены педалить простыни однотипного кода

                                        У васт большой опыт написания программ на C, да? В моём коде вы предложили сократитить 2 повтора по 2 строки лямбдой в 5 строк и плюс по одной стоке на каждый повтор вместо двух. Ваш код стал менее читаемым, длинее и дольше в написании… Вы повторяете стереотипы по поводу C, которые к реальности не имеют ни какого отношения…

                                        Ну пусть каждый выбирает для себя.

                                        Вот именно. Я изначально выссказал своё мнение, своё отношение и неоднократно акцентировал на этом внимание…


                                        1. eao197
                                          03.10.2017 13:24

                                          Вы используете brainfuck в работе?
                                          Для демонстрации ошибочности вашего утверждения этого не требуется. Ну если хотите примеров того, что люди используют в работе, то посмотрите на какой-нибудь Q или J.
                                          Можете пояснить, что конкретно вы имеете в виду?
                                          Если вы вынуждены плотно заниматься сетевым программированием на чистом C и привыкли это делать так, как разработчики nginx, то у вас может просто «глаз замылиться». Ну и парадокс Блаб-программиста так же может иметь место быть.
                                          У васт большой опыт написания программ на C, да?
                                          Возможно, опыт написания программ у меня просто больше, чем у вас. Если вы говорили про 1997-ой год, то точно больше. Ну и C был одним из тех языков, с которых приходилось начинать. И ушел я с него при первой же возможности, т.к. даже в начале 90-х было понятно, что использовать C по собственной воле могут не только лишь все.
                                          В моём коде вы предложили сократитить 2 повтора по 2 строки лямбдой в 5 строк и плюс по одной стоке на каждый повтор вместо двух.
                                          Вообще-то три повтора. В двух из которых еще и нужно было функцию очистки явным образом вызывать. И если вы в лямбде насчитали пять строк, то у вас еще и проблемы со зрением.
                                          Ваш код стал менее читаемым, длинее и дольше в написании…
                                          Ну тогда понятно. Вопросов больше не имею.


                                          1. saterenko
                                            03.10.2017 13:41

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

                                            В чём оно ошибочное? Сложность синтаксиса языка не отрицает того, что сложная для понимания программа или простая — это результат работы программиста.
                                            Если вы вынуждены плотно заниматься сетевым программированием на чистом C и привыкли это делать так, как разработчики nginx, то у вас может просто «глаз замылиться». Ну и парадокс Блаб-программиста так же может иметь место быть.

                                            Игорь не был вынужден, это было его хобби и он был волен в выборе языка. Фразы «глаз замылиться» и «парадокс Блаб-программиста» не делают понятнее то, что вы хотите сказать…
                                            Возможно, опыт написания программ у меня просто больше, чем у вас. Если вы говорили про 1997-ой год, то точно больше. Ну и C был одним из тех языков, с которых приходилось начинать. И ушел я с него при первой же возможности, т.к. даже в начале 90-х было понятно, что использовать C по собственной воле могут не только лишь все.

                                            На C с 97-го, а так с 92-го, бейсик, ассемблер, паскаль, пролог… Тут, видимо, кому что, я неоднократно пытался перейти на C++ в своих проекта, так как у него объективно есть плюсы, но не лежит душа… На вкус и цвет…
                                            Вообще-то три повтора. В двух из которых еще и нужно было функцию очистки явным образом вызывать.

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

                                            Давайте посчитаем вместе:
                                            const auto log_and_return_null = [&](const char * msg) 
                                            {
                                              cor_log_error(log, msg);
                                              return nullptr;
                                             };

                                            Я насчитал 5 строк. У вас меньше?
                                            Ну тогда понятно. Вопросов больше не имею

                                            Действительно, теперь всё понятно ))


                                            1. eao197
                                              03.10.2017 14:01

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

                                              И смотрим на пример программы на J:
                                              quicksort=: (($:@(<#[), (=#[), $:@(>#[)) ({~ ?@#)) ^: (1<#)

                                              Вряд ли в этой программе есть что-то сложное, обычный такой quick sort. Сложным для восприятие ее сделал не программист, а синтаксис языка программирования.
                                              Фразы «глаз замылиться» и «парадокс Блаб-программиста» не делают понятнее то, что вы хотите сказать…
                                              Ну извините, разжевывать еще подробнее нет желания.

                                              По поводу количества строк. Скобки нет смысла считать. Так что там всего три строки. Но если вы хотите подсчитать скобки, то будет либо 4, либо 5, в зависимости от расположения открывающей. Но подобный подсчет выглядит еще более тупым занятием, чем попытки сравнить простоту и выразительность C-шного и C++ного кода.


                                              1. saterenko
                                                03.10.2017 14:19

                                                Вряд ли в этой программе есть что-то сложное, обычный такой quick sort. Сложным для восприятие ее сделал не программист, а синтаксис языка программирования.

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

                                                «Если вы ученый, квантовый физик и не можете в двух словах объяснить пятилетнему ребенку, чем вы занимаетесь, — вы шарлатан» Ричард Фейнман.
                                                По поводу количества строк. Скобки нет смысла считать. Так что там всего три строки. Но если вы хотите подсчитать скобки, то будет либо 4, либо 5, в зависимости от расположения открывающей. Но подобный подсчет выглядит еще более тупым занятием, чем попытки сравнить простоту и выразительность C-шного и C++ного кода.

                                                Ну т.е. я не слепой, а вы меня оклеветали, так? )))

                                                Не вижу смысла дальше продолжать эту дискуссию…


                                                1. eao197
                                                  03.10.2017 14:28

                                                  Проблема даже не в том, что я не ученый. А в том, что вы не пятилетний ребенок. И объяснять вам простые вещи у меня уже нет ни желания, ни терпения. Равно как и учить вас считать строки.


                                        1. 0xd34df00d
                                          03.10.2017 20:11
                                          +1

                                          Ваш код стал менее читаемым, длинее и дольше в написании

                                          Для вас. Для меня — нет, например.

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


                        1. Antervis
                          03.10.2017 13:53
                          +1

                          В серьёзном проекте вы не обойдётесь без внешних зависимостей

                          Да. Но желательно обходиться минимумом. Потому что каждая внешняя библиотека это потенциальные проблемы:
                          1. усложнение процесса сборки (писал)
                          2. усложнение процесса деплоя (писал)
                          3. в библиотеках от версии к версии может меняться API
                          4. библиотеки могут устаревать (например, прекращается поддержка и их уже не собрать новым компилятором)
                          5. библиотеки могут распространяться не под все поддерживаемые платформы
                          6. в них могут появляться и исправляться ошибки.
                          7. даже если ошибок в самих библиотеках нет, их еще надо корректно использовать


                          1. saterenko
                            03.10.2017 13:58

                            Это справедливо, но всё это гипотезы, так ведь? И они не говорят в пользую C или C++, это отдельная проблема, которая существует в обоих языках… Хотя я, на своей практике, столкнулся с подобным лишь однажды в клиенте к mongodb, где появился варнинг о том, что функция стала deprecated…


                            1. Antervis
                              03.10.2017 15:21
                              +1

                              нет, не гипотезы. Мне доводилось переводить несколько проектов на более поздние версии Qt, например. И большая часть проблем была связана даже не с самим Qt, а с библиотеками, его использовавшими и пакетами в системе. Например, qwt 5 -> 6.

                              Есть проект, у которого коллеге пришлось убирать зависимость от Qt. Если вы не пробовали — просто скажу, что это боль.

                              У нас используется сервер сборки. Каждая доп. зависимость должна быть отражена еще и там. С этим тоже бывают проблемы.

                              Бывают проблемы вида «старая версия библиотеки не собирается более новым компилятором, а в новой что-то не работает». Такое было недавно с boost

                              Так что из личного опыта: число зависимостей надо сводить к аскетичному минимуму.


                              1. saterenko
                                03.10.2017 16:02

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

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


  1. laughman
    29.09.2017 11:26

    вы написали функцию inline/force_inline, 100 раз её использовали, а компилятор решил её не встраивать — линкер выкинет 99 скомпилированных тел вашей функции и оставит одно

    кмк, если компилятор решит не встраивать, он и оставит одно тело


    1. antoshkka Автор
      29.09.2017 12:15
      +1

      Да, компилятор оставит тело в каждой единице трансляции где эта функция была объявлена. Линкер, при объединении единиц трансляций, будет выкидывать одинаковые weak функции.

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


  1. erwins22
    29.09.2017 12:45

    Лучше бы пошли по пути ликвидации неопределенного поведения.
    Т.е. Четко формулировать где когда какой результат или где выдавать ошибку.


    1. khim
      29.09.2017 12:54
      +1

      Извините, но и C# и Java — уже есть.


      1. erwins22
        29.09.2017 14:46

        вы говорите так, как будто неопределенное поведение это хорошо.


        1. khim
          29.09.2017 18:43

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

          В C# и Java принят другой подход — ну ради бога. Но зачем его тащить в C/C++?


          1. erwins22
            30.09.2017 11:51
            -1

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


            1. khim
              30.09.2017 18:57

              потому что множество разбросанных граблей не делает язык хорошим.
              Это смотря какая у вас цель. Если у вас цель — безопасный язык, то вам не сюда: ни один язык с free/delete не может быть безопасным. А если вам нужны переносимые программы — так UB это первейший помощник: они заставляют программиста писать программы так, что их легко потом скомпилировать.

              И для стат анализа это гемор.
              Смотря для какого. Для компиляторного — как раз наоборот: чем больше UB — тем лучше. Так как он на UB (вернее на отсутствие UB — не забываем, чья обязанность с ними бороться, да?) полагается в своём анализе очень сильно.


  1. egordeev
    29.09.2017 12:51

    Здравствуйте, а в C++20 не планируется добавить software transactional memory?


    1. antoshkka Автор
      29.09.2017 13:05

      У SG5 есть идея выпустить техническую спецификацию на TM к C++20, но не понятно успеют ли по срокам. Эта же подгруппа занимается executors и новыми классами для синхронизации, работы у них и очень много.


      1. antoshkka Автор
        29.09.2017 13:18

        Поправочка:
        * люди из этой же подгруппы занимаются executors и новыми классами для синхронизации…


  1. pilot911
    29.09.2017 12:57

    понравилась серия уроков от Яндекса по C++, где с самого начала учат простым и практичным вещам… вот интересно, сколько лет надо потратить, чтобы перейти с этого уровня уроков к пониманию всех этих корутин, сопрограмм и тп?


    1. mayorovp
      29.09.2017 13:19
      +1

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


      1. DistortNeo
        29.09.2017 14:09

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


        1. mayorovp
          29.09.2017 14:10

          Внутренние механизмы собственно корутин и сопрограмм просты.

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


          1. DistortNeo
            29.09.2017 14:50
            +1

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


  1. DaylightIsBurning
    29.09.2017 13:29

    P0458R0 — функция contains(key) member для классов [unordered_]map/set/multimap/multiset.
    А чем count() не угодил?


    1. mayorovp
      29.09.2017 13:35
      +1

      Хотя бы названием.


      1. DaylightIsBurning
        29.09.2017 13:37

        разве что. Просто в предложении идёт сравнение с

        if (some_set.find(element) != some_set.end()) {
            // ...
        }
        что несколько притянуто за уши, т.к. есть count()


        1. DaylightIsBurning
          29.09.2017 13:46
          +2

          моя ошибка, невнимательно читал proposal:

          ...count method. Unfortunately, it's use is suboptimal for multisets and multimaps (it has greater complexity than find).


  1. sergey-b
    29.09.2017 14:10

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


    1. alexeykuzmin0
      29.09.2017 14:51
      -1

      Нет, нельзя. Останется директива #import.


      1. sergey-b
        29.09.2017 14:57

        Вы уверены? Там по ссылке на документ нет ни одного упоминания о препроцессоре и import — новое ключевое слово без решетки.


        1. alexeykuzmin0
          29.09.2017 14:58

          Действительно, я ошибся.


          1. sergey-b
            29.09.2017 15:01

            Я имел в виду, останется ли что-то, для чего нужен препроцессор, когда станет устаревшей директива #include?


            1. bamovetz
              29.09.2017 17:44
              +1

              Я думаю условная компиляция никуда не денется. Ибо удобно для кроссплатформы.


              1. sergey-b
                29.09.2017 17:54
                +1

                Ну смотря какая. Если я у себя поставил ifdef, а потом он включился неожиданно для меня, потому что в одном из 20 модулей, которые притянулись неявно по цепочке, включается макрос с этим именем, то может быть такая условная компиляция в современном языке программирования не очень нужна?


                1. bamovetz
                  29.09.2017 18:59
                  +2

                  Именно поэтому макросы не экспортируются из модулей.


                  1. sergey-b
                    29.09.2017 19:25

                    То есть вот такие штуки пока остаются?

                    #define SUM(a, b) a + b
                    #define SQRT(a, b) a * a
                    


                    1. mayorovp
                      29.09.2017 19:29
                      +6

                      За такие штуки надо убивать. Особенно за вторую.


                      1. sergey-b
                        29.09.2017 19:32
                        -1

                        Почему бы не убрать их из языка?


                        1. mayorovp
                          29.09.2017 19:33
                          +1

                          Потому что существуют программы, которые их используют


                      1. captain_obvious
                        29.09.2017 20:20
                        +1

                        Да и первая хороша
                        SUM(a, b) * SUM(c, d) == a + b*c + d


                1. Kobalt_x
                  29.09.2017 20:43

                  Ну бусту же нужно будет как-то поставлять модули для различных C++20 компиляторов во времена C++26


              1. 0xd34df00d
                30.09.2017 01:03

                if constexpr?


                Он более строг, чем препроцессорный #if, но я не могу сходу придумать случая, где это было бы важно.


                1. khim
                  30.09.2017 01:54

                  Да тривиальная векторизация, к примеру. На ARM — у вас будет, скажем, int32x4_t, при использовании SSE — __m128, а если вы захотите использовать AVX — то вам нужно будет использовать __m256 и «разложить» данные по-другому.

                  И как вы это в if constexpr вложите, я извиняюсь?


                  1. 0xd34df00d
                    30.09.2017 02:05

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


                    1. khim
                      30.09.2017 02:49
                      +1

                      На самом деле if constexpr выглядит примерно как метапрограммирование в C++98: всё, в принципе, делается — но жутко неудобно и «через одно место». В частности проблему выбора типов можно решить если вернуть указатель на нужный, а потом к соответствующей функции decltype применить, но если вы после этого кроме AVX/NEON/SSE захотите ещё и «чисто скалярную версию» поддержать — то вам нужно будет весьма кривые трюки применять.

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


                      1. 0xd34df00d
                        30.09.2017 19:35
                        +1

                        Я вообще не понимаю регулярно вылезающих мелких косяков в стандарте. Вот кто мешает разрешить делать if constexpr вне функций, например? Или вот вышел C++11 с using-алиасами, а всякие std::enable_if_t появились только в C++14. Или вот вышел C++14 с variable templates, а всякие std::is_same_v появились только в С++17.


                        1. khim
                          30.09.2017 19:51
                          +1

                          Я вообще не понимаю регулярно вылезающих мелких косяков в стандарте
                          Никто не хочет повторения истории с export template — когда в стандарте написали, а реализовать потом толком не смогли.

                          Вот кто мешает разрешить делать if constexpr вне функций, например?
                          Ну мало ли какие у разработчиков разных компиляторов заморочки. Просто не подумали, скорее всего. Да и вот это вот тоже как костыль выглядит:
                          template<class T> struct dependent_false : std::false_type {};
                          template <typename T>
                          void f() {
                               if constexpr (std::is_arithmetic_v<T>)
                                   // ...
                               else
                                 static_assert(dependent_false<T>::value, "Must be arithmetic"); // ok
                          }


                          Или вот вышел C++11 с using-алиасами, а всякие std::enable_if_t появились только в C++14. Или вот вышел C++14 с variable templates, а всякие std::is_same_v появились только в С++17.
                          Ну это как раз понятно: выходит сначала базовый функционал, потом вспомогательный. Чтобы не было перерывов в полтора десятилетия как между C++98 и C++11


                          1. 0xd34df00d
                            01.10.2017 01:53

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

                            Один из ранних пропозалов, что я читал, как раз подразумевал и такое, если я правильно помню.

                            Ну это как раз понятно: выходит сначала базовый функционал, потом вспомогательный. Чтобы не было перерывов в полтора десятилетия как между C++98 и C++11

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


                            1. khim
                              01.10.2017 16:50
                              +1

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

                              Сложные же вещи зачастую имеют только одну реализацию, которую можно принять или не принять — и всё. Закон тривиальности в действии.


    1. DistortNeo
      29.09.2017 20:55

      Не совсем так. Модуль — это набор препроцессированных h-ников + lib-файл в одном флаконе.
      Для использования модуля его все равно придётся сначала скомпилировать из исходников, тут-то условная компиляция и вылезет.


      1. Kobalt_x
        29.09.2017 21:12

        тут ещё вопрос конвертации h файла в модуль, под каждый условный дефайн генерить свой модуль?


        1. DistortNeo
          29.09.2017 21:23
          +2

          Ну да. Вы же перекомпилируете программу, когда меняете дефайны?


          1. Kobalt_x
            30.09.2017 19:47

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


  1. amarao
    29.09.2017 16:35
    +2

    Когда в C++42 реализуют unsafe, защиту от NULL dereference в безопасном коде, понятие владения памятью, алгебраические типы данных?


    1. alexeykuzmin0
      29.09.2017 16:48

      Уже в процессе — почитайте C++ Core guidelines. Их смысл в том, чтобы выделить «безопасное подмножество» C++, чтобы в подавляющем большинстве случаев все писали лишь на нем, инкапсулируя использование остальных возможностей языка. Правда, новые конструкции в core guidelines вводятся не в язык, а в специальную header-only библиотеку (очень маленькую), а проверка правил осуществляется не компилятором, а статическим анализатором (впрочем, входящим в состав того же visual studio или clang), но это уже мелочи, не правда ли?

      Конкретно про null dereference и владение памятью — пункты I.11, I.12, F.7, F.26, F.27 и некоторые другие. Про unsafe — пункт I.30.
      А алгебраические типы данных, насколько я понимаю, тот же самый std::variant, вид в профиль.


      1. amarao
        30.09.2017 18:39
        +3

        Я на самом деле намекал на Rust.


  1. Amomum
    30.09.2017 12:48
    +3

    Можно будет инициализировать поля структур, прям как в чистом C:

    struct foo { int a; int b; int c; };
    foo b{.a = 1, .b = 2};

    Господи, дождались!


    1. khim
      30.09.2017 19:06

      Будем надеяться, что эту конкретную фичу реализуют до 2020го, так как в clang'е оно работает уже давно (clang 3.0 точно так умеет, не знаю насчёт clang 2.x) и мы регулярно встречаем код, который GCC или MSVC не собрать из-за этого…


      1. Amomum
        01.10.2017 19:31

        Странно, только что проверил gcc 6.3 — собирает.
        Другое дело, что использовать нестандартные расширения языка, на мой взгляд, не лучшее решение. Я обычно просто запихивал такие инициализации в файлы.с.


        1. khim
          01.10.2017 22:55

          Странно, только что проверил gcc 6.3 — собирает.
          Мы ушли с GCC после GCC 4.6. А оказывается GCC 4.7 тоже так умеет.

          Они хотя бы в release notes это упомянули бы, что ли…

          Другое дело, что использовать нестандартные расширения языка, на мой взгляд, не лучшее решение.
          Теперь можно с чистой совестью говорить, что вы просто используете стандартную фичу из C++20


      1. monah_tuk
        02.10.2017 06:29
        +1

        А вы попробуйте немного другой код:


        foo b{.c = 2};

        и опцию -pedantic. И Gcc такое уже не собирает: "sorry, unimplemented: non-trivial designated initializers not supported".


    1. monah_tuk
      02.10.2017 06:25

      Правда все компиляторы таки ругаются на такое использованием: https://wandbox.org/permlink/D75xMWgpGfXi1PMU


      ЗЫ по ссылке пример использования данной фичи как альтернативы именованных аргументов функции.


      1. khim
        02.10.2017 12:40

        Странно — у меня работает начиная с clang 3.3 (не обращайте внимание на замену на <stdio.h>: на godbolt.org используются новые библиотеки libstd++ со старым clang'ом, так что стандартную библиотеку в столь древних версиях clang'а использовать не получается).


        1. monah_tuk
          03.10.2017 01:28

          Шланг собирает. Gcc — нет. Без -pedantic даже не ругается, а с ним — как по ссылке у меня.


          1. khim
            03.10.2017 02:38

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

            Хуже, что он не позволяет опускать поля и указывать только подмножество (как в предложении для C++20). Без этого, как бы, смысл совсем теряется…


            1. monah_tuk
              03.10.2017 03:10

              Я к тому, что сейчас, так или иначе, это реализовано (если реализовано, привет Gcc!) не как часть предложения для C++20, а как часть функционала C99, эдакое расширение.


              Хуже, что он не позволяет опускать поля и указывать только подмножество (как в предложении для C++20). Без этого, как бы, смысл совсем теряется…

              только Gcc. Шланг может и без -pedantic вполне можно пощупать, как оно будет. Другое дело, что оно реализовано не в соответствии с предложением для C++20, а как в C99.


  1. TargetSan
    03.10.2017 11:12
    +2

    Подскажите пожалуйста кто в курсе по поводу двух особенностей модулей:


    Своя нотация именования


    // <root>/src/Module1.cpp
    module foo.bar;
    // ...
    // <root>/src/dir1/Module2.cpp
    module foo;
    import foo.bar;

    Вместо того, чтобы сделать простой и понятный импорт по относительным путям


    // <root>/src/Module1.cpp
    import "Dir1/Module2"; // See below
    // some code goes here
    
    // ...
    // <root>/src/Dir1/Module2.cpp
    import "std/vector";
    // some code with exports goes here

    Это КМК решило бы сразу несколько проблем — не нужно явно указывать имя модуля, пути импорта понятны из кода, плюс естественная возможность приватных модулей. Если вы скажете "а как же многофайловые модули?" — а зачем они вообще нужны? Откровенно выглядит как костыль. Генерацию интерфейсной части из общего текста модуля можно как раз оставить на совести компилятора.


    Глобальный модуль


    В черновике упомянут некий "глобальный модуль", в который входит весь код до декларации module. Этот двойной пассаж мне честно говоря не понятен. Единственное подозрение — необходимость куда-то деть содержимое файла до декларации модуля.


    Я попытался спросить в общей гугл группе https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-proposals/SdgWgJCR35s, но мне к сожалению так никто и не ответил.


  1. DistortNeo
    03.10.2017 11:34

    > Если вы скажете «а как же многофайловые модули?» — а зачем они вообще нужны?

    Потому что это удобно. Неприятно работать с одним файлом на 10к строчек.


    1. TargetSan
      03.10.2017 12:20
      +2

      Потому что это удобно. Неприятно работать с одним файлом на 10к строчек.

      Эмм, просто поделить на несколько вложенных модулей? С указанным подходом это будет тривиально.


      1. DistortNeo
        03.10.2017 12:37

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


        1. TargetSan
          03.10.2017 12:49

          Да, придётся добавить к таким функциям export. Зато будет понятно, где что лежит. При описанном вами сценарии с модулем в 10К строчек, делённым на несколько файлов, придётся ещё выяснять где лежит каждый кусок — т.к. логическое имя модуля вообще никак не связано с его местоположением в исходниках.


          1. DistortNeo
            03.10.2017 14:24

            В том-то и прикол, что модуль — это не исходник. Считайте, что модуль — это lib-файл, но с дополнительным экспортом объявлений классов. Хотите открыть исходники — не вопрос, IDE в помощь. Именно так всё выглядит в том же C#, и это удобно и устраивает всех, т.к. необходимости лезть в исходники библиотеки обычно не возникает.


            1. TargetSan
              03.10.2017 15:33

              Тогда я не понимаю, какой уровень призваны организовать модули. Если уровень юнитов трансляции — то где, действительно, возможность организовать приватные детали реализации, и зачем такие с мультифайловостью и отдельным именованием? Если же уровень единиц сборки — зачем отдельно декларировать везде имя модуля, и что будет, если несколько модулей лягут в один бинарь?


        1. 0xd34df00d
          03.10.2017 21:07

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

          В хаскеле с этим проблемы, кстати, и решения весьма костыльные.


  1. TargetSan
    04.10.2017 11:25
    +2

    Уважаемый antoshkka, у вас случайно нет "человекочитаемого" описания текущего состояния по модулям — на каком уровне они существуют (грубо — единица трансляции или линковки), как предполагается существующий код с инклюдами приводить к модульному виду и т.п. Судя по https://habrahabr.ru/company/yandex/blog/336264/#comment_10449246, понимания, как оно должно быть, нет как минимум у меня.


    1. iassasin
      04.10.2017 17:55

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