Недавно в финском городе Оулу завершилась встреча международной рабочей группы WG21 по стандартизации C++, в которой впервые официально участвовали сотрудники Яндекса. На ней утвердили черновой вариант C++17 со множеством новых классов, методов и полезных нововведений языка.



Во время поездки мы обедали с Бьярне Строуструпом, катались в лифте с Гербом Саттером, жали руку Беману Дейвсу, выходили «подышать воздухом» с Винцентом Боте, обсуждали онлайн-игры с Гором Нишановым, были на приёме в мэрии Оулу и общались с мэром. А ещё мы вместе со всеми с 8:30 до 17:30 работали над новым стандартом C++, зачастую собираясь в 20:00, чтобы ещё четыре часика поработать и успеть добавить пару хороших вещей.

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

if constexpr (condition)


В C++17 появилась возможность на этапе компиляции выполнять if:

template <std::size_t I, class F, class S>
auto rget(const std::pair<F, S>& p) {
    if constexpr (I == 0) {
        return p.second;
    } else {
        return p.first;
    }
}

При этом неактиваная ветка ветвления не влияет на определение возвращаемого значения. Другими словами, данный пример скомпилируется и:
  • при вызове rget<0>( std::pair<char*, short>{} ) тип возвращаемого значения будет short;
  • при вызове rget<1>( std::pair<char*, short>{} ) тип возвращаемого значения будет char*.

T& container::emplace_back(Args&&...)


Методы emplace_back(Args&&...) для sequence контейнеров теперь возвращают ссылку на созданый элемент:
// C++11
some_vector.emplace_back();
some_vector.back().do_something();

// C++17
some_vector.emplace_back().do_something();

std::variant<T...>


Позвольте представить: std::variant<T...> — union, который помнит что хранит.
std::variant<int, std::string> v;
v = "Hello word";
assert(std::get<std::string>(v) == "Hello word");
v = 17 * 42;
assert(std::get<0>(v) == 17 * 42);

Дизайн основан на boost::variant, но при этом убраны все известные недочёты последнего:

  • std::variant никогда не аллоцирует память для собственных нужд;
  • множество методов std::variant являются constexpr, так что его можно использовать в constexpr выражениях;
  • std::variant умеет делать emplace;
  • к хранимому значению можно обращаться по индексу или по типу — кому как больше нравится;
  • std::variant не нуждается в boost::static_visitor;
  • std::variant не умеет рекурсивно держать в себе себя (например функционал наподобие `boost::make_recursive_variant<int, std::vector< boost::recursive_variant_ >>::type` убран).

Многопоточные алгоритмы


Практически все алгоритмы из заголовочного файла были продублированы в виде версий, принимающих ExecutionPolicy. Теперь, например, можно выполнять алгоритмы многопоточно:
std::vector<int> v;
v.reserve(100500 * 1024);
some_function_that_fills_vector(v);

// Многопоточная сортировка данных
std::sort(std::execution::par, v.begin(), v.end());

Осторожно: если внутри алгоритма, принимающего ExecutionPolicy, вы кидаете исключение и не ловите его, то программа завершится с вызовом std::terminate():
std::sort(std::execution::par, v.begin(), v.end(), [](auto left, auto right) {
    if (left==right)
        throw std::logic_error("Equal values are not expected"); // вызовет std::terminate()

    return left < right;
});


Доступ к нодам контейнера


Давайте напишем многопоточную очередь с приоритетом. Класс очереди должен уметь потокобезопасно сохранять в себе множество значений с помощью метода push и потокобезопасно выдавать значения в определенном порядке с помощью метода pop():
// C++11
void push(std::multiset<value_type>&& items) {
    std::unique_lock<std::mutex> lock(values_mutex_);
    for (auto&& val : items) {
        // аллоцирует память, может кидать исключения
        values_.insert(val);
    }

    cond_.notify_one();
}

value_type pop() {
    std::unique_lock<std::mutex> lock(values_mutex_);
    while (values_.empty()) {
        cond_.wait(lock);
    }

    // аллоцирет память, может кидать исключения
    value_type ret = *values_.begin();
    // деаллоцирует память
    values_.erase(values_.begin());

    return ret;
}
// C++17
void push(std::multiset<value_type>&& items) {
    std::unique_lock<std::mutex> lock(values_mutex_);

    // не аллоцирует память, не кидает исключения.
    // работает намного быстрее (см. #2)
    values_.merge(std::move(items));

    cond_.notify_one();
}

value_type pop() {
    std::unique_lock<std::mutex> lock(values_mutex_);
    while (values_.empty()) {
        cond_.wait(lock);
    }

    // не аллоцирет память и не кидает исключения (см. #2)
    auto node = values_.extract(values_.begin());
    lock.unlock();

    // извлекаем значение из ноды multiset'а
    return std::move(node.value());
}

В C++17 многие контейнеры обзавелись возможностью передавать свои внутренние структуры для хранения данных наружу, обмениваться ими друг с другом без дополнительных копирований и аллокаций. Именно это происходит в методе pop() в примере:
// Извлекаем из rbtree контейнера его 'ноду' (tree-node)
auto node = values_.extract(values_.begin());

// Теперь values_ не содрежит в себе первого элемента, этот элемент полностью переехал в node
// values_mutex_ синхронизирует доступ к values_. раз мы вынули из этого контейнера
// интересующую нас ноду, для дальнейшей работы с нодой нет необходимости держать блокировку.
lock.unlock();

// Наружу нам необходимо вернуть только элемент, а не всю ноду. Делаем std::move элемента из ноды.
return std::move(node.value());

// здесь вызовется деструктор для ноды

Таким образом наша многопоточная очередь в C++17 стала:
  • более производительной — за счёт уменьшения количества динамических аллокаций и уменьшения времени, которое программа проводит в критической секции;
  • более безопасной — за счёт уменьшения количества мест, кидающих исключения, и за счет меньшего количества аллокаций;
  • менее требовательной к памяти.

Автоматическое определение шаблонных параметров для классов


В черновик C++17 добавили автоматическое определение шаблонных параметров для шаблонных классов. Это значит, что простые шаблонные классы, конструктор которых явно использует шаблонный параметр, теперь автоматически определяют свой тип:
Было Стало
std::pair<int, double> p(17, 42.0);
std::pair p(17, 42.0);
std::lock_guard<std::shared_timed_mutex> lck(mut_);
std::lock_guard lck(mut_);
std::lock_guard<std::shared_timed_mutex> lck(mut_);
auto lck = std::lock_guard(mut_);

std::string_view


Продолжаем эксурс в дивный мир C++17. Давайте посмотрим на следующую C++11 функцию, печатающую сообщение на экран:
// C++11
#include <string>
void get_vendor_from_id(const std::string& id) { // аллоцирует память, если большой массив символов передан на вход вместо std::string
    std::cout <<
        id.substr(0, id.find_last_of(':')); // аллоцирует память при создании больших подстрок
}

// TODO: дописать get_vendor_from_id(const char* id) чтобы избавиться от динамической аллокации памяти

В C++17 можно написать лучше:
// C++17
#include <string_view>
void get_vendor_from_id(std::string_view id) { // не аллоцирует память, работает с `const char*`, `char*`, `const std::string&` и т.д.
    std::cout <<
        id.substr(0, id.find_last_of(':')); // не аллоцирует память для подстрок
}

std::basic_string_view или std::string_view — это класс, не владеющий строкой, но хранящий указатель на начало строки и её размер. Класс пришел в стандарт из Boost, где он назывался boost::basic_string_ref или boost::string_ref.

std::string_view уже давно обосновался в черновиках C++17, однако именно на последнем собрании было решено исправить его взимодействие с std::string. Теперь файл <string_view> может не подключать файл <string>, за счет чего использование std::string_view становится более легковесным и компиляция программы происходит немного быстрее.

Рекомендации:
  • используйте единственную функцию, принимающую string_view, вместо перегруженных функций, принимающих const std::string&, const char* и т.д.;
  • передавайте string_view по копии (нет необходимости писать `const string_view& id`, достаточно просто `string_view id`).

Осторожно: string_view не гарантирует, что строчка, которая в нем хранится, оканчивается на символ '\0', так что не стоит использовать функции наподобие string_view::data() в местах, где необходимо передавать нуль-терминированные строчки.

if (init; condition)


Давайте рассмотрим следующий пример функции с критической секцией:
// C++11
void foo() {
    // ...
    {
        std::lock_guard<std::mutex> lock(m);
        if (!container.empty()) {
            // do something
        }
    }
    // ...
}

Многим людям такая конструкция не нравилась, пустые скобки выглядят не очень красиво. Поэтому в C++17 решено было сделать всё красивее:
// C++17
void foo() {
    // ...
    if (std::lock_guard lock(m); !container.empty()) {
        // do something
    }
    // ...
}

В приведенном выше примере переменная lock будет существовать до закрывающей фигурной скобки оператора if.

Structured bindings


std::set<int> s;
// ...

auto [it, ok] = s.insert(42); 
// Теперь it — итератор на вставленный элемент; ok - bool переменная с результатом.
if (!ok) {
    throw std::logic_error("42 is already in set");
}
s.insert(it, 43);
// ...

Structured bindings работает не только с std::pair или std::tuple, а с любыми структурами:
struct my_struct { std::string s; int i; };
my_struct my_function();
// ...

auto [str, integer] = my_function();

А ещё...


В C++17 так же есть:
  • синтаксис наподобие template <auto I> struct my_class{ /*… */ };
  • filesystem — классы и функции для кросплатформенной работы с файловой системой;
  • std::to_chars/std::from_chars — методы для очень быстрых преобразований чисел в строки и строк в числа с использованием C локали;
  • std::has_unique_object_representations <T> — type_trait, помогающий определять «уникальную-представимость» типа в бинарном виде;
  • new для типов с alignment большим, чем стандартный;
  • inline для переменных — если в разных единицах трансляции присутствует переменная с внешней линковкой с одним и тем же именем, то оставить и использовать только одну переменную (без inline будет ошибка линковки);
  • std::not_fn коректно работающий с operator() const&, operator() && и т.д.;
  • зафиксирован порядок выполнения некоторых операций. Например, если есть выражение, содержащее =, то сначала выполнится его правая часть, потом — левая;
  • гарантированный copy elision;
  • огромное количество математических функций;
  • std::string::data(), возвращающий неконстантый char* (УРА!);
  • constexpr для итераторов, std::array и вспомогательных функций (моя фишечка :);
  • явная пометка старья типа std::iterator, std::is_literal_type, std::allocator<void>, std::get_temporary_buffer и т.д. как deprecated;
  • удаление функций, принимающих аллокаторы из std::function;
  • std::any — класс для хранения любых значений;
  • std::optional — класс, хранящий определенное значение, либо флаг, что значения нет;
  • fallthrough, nodiscard, maybe_unused;
  • constexpr лямбды;
  • лямбды с [*this]( /*… */ ){ /*… */ };
  • полиморфные алокаторы — type-erased алокаторы, отличное решение, чтобы передавать свои алокаторы в чужие библиотеки;
  • lock_guard, работающий сразу со множеством мьютексов;
  • многое другое.


Напоследок


На конференции C++Siberia в августе мы постараемся рассказать о новинках С++ с большим количеством примеров, объяснить, почему именно такой дизайн был выбран, ответим на ваши вопросы и упомянем множество других мелочей, которые невозможно поместить в статью.
Расскажите о чём бы вам было интересно почитать

Проголосовало 477 человек. Воздержалось 155 человек.

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

Поделиться с друзьями
-->

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


  1. mezastel
    13.07.2016 19:54
    +21

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


  1. antoshkka
    13.07.2016 20:04
    +3

    Модули уже почти готовы (по крайней мере дело дошло до wording — «патча» к существующему стандарту). Если не будет найдено фатальных недостатков, то есть все шансы увидеть модули в C++Next.


    1. mezastel
      13.07.2016 20:57
      +5

      Да, но это еще минимум до 2020 ждать. Формально. Я конечно надеюсь что хотя бы Microsoft сделают их побыстрее (уже есть подвижки), но хочется везде и немедленно. И в связи с этим куча всяких вопрос: например, сможем ли мы выкинуть на помойку CРР/HPP файлы и просто иметь CPP и всё? Потому что это уже надоело, и самое главное что по стандарту много чего нельзя делать header only, например специализации шаблонов.

      Еще конечно хочется полностью новый STL. Текущая стандартная библиотека мне видится тупиком. Взять хотя бы std::string — на CppNow, Sean Parent рассказывал что у них там 4 реализации строк в коде. А все почему? Потому что обычный API этой строки убогий, а выкинуть и сказать «мы накосячили, давайте заново» никто не готов.


      1. antoshkka
        13.07.2016 21:57
        +1

        Еще конечно хочется полностью новый STL

        В Оулу решено было забронировать все namespace stdцифры для будущего использования стандартной библиотекой. Тоесть когда-нибудь и правда может появиться std2::. У людей в комитете уже сейчас есть идеи для новой версии стандартной библиотеки. Но вот появится она наврядли в ближайшие 10 лет.


      1. zelyony
        13.07.2016 22:16
        +3

        да уж, 30 лет не могут сделать нормальные строчки — поиск, замена, lower/upper/locale
        30 лет «ходим на костылях», а комитет грезит о дальнем космосе
        запилить строки, синхронизацию, работу с файлами и сетью (+ асинки) — закроет 95% потребностей программистов
        одну либку возмешь, она зависит от boost::asio, другая с необходимыми вещами, что нет в первой — от libevent… кто-то еще притянул ProtoBuf, а еще один решил, что для разных клиентов будет удобнее Thrift(с их сервисами и транспортами)… в итоге в приложении 3-4 либки работы с сетью (неплохо бы еще ZeroMQ с подписками и RabbitMQ для message-queue), 2-3 вида строк и 5-6 реализаций мьютексов и умных указателей… рукалицо/больпечаль

        что касается новой STL из-за строк, то это ты погорячился: достаточно одобрить extension methods и впилить icu-либку, уже будет счастье:
        string toLower( string_view sv ) {… }
        auto str = string(«Hello WORLD!»).toLower();

        offtopic: конечно в узкоспециализированных вещах С++ замены нет, но НЕ для «железного» уровня рассматриваю C++ как низкоуровневую(нативную, шуструю) реализацию некоторых вещей для более удобной/человеческой(созданной для людей) среды, что-то вроде С++ — это интринсики для C#/Java (еще бы их interop был гладкий… мечты)


        1. VioletGiraffe
          13.07.2016 22:23
          +3

          Чёрт бы с поиском-заменой, сами напишем. Дайте поддержку UTF-8 строк! Именно строк как набора символов, а не байт. ЧТоб итерирование работало посимвольно и т. д.


          1. antoshkka
            13.07.2016 22:36
            +2

            Есть годные на мой взгляд предложения, но до них не дошли руки и в C++17 их не будет :(


            1. monah_tuk
              14.07.2016 13:29
              +1

              Можно ссылки? Я волшебное слово знаю — ДАЙ! пожалуйста!


              1. antoshkka
                14.07.2016 14:47
                +1

                Самое толковое на сегодняшний момент http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0244r1.html.


                1. monah_tuk
                  15.07.2016 04:58

                  Спасибо!


          1. Rezzet
            14.07.2016 00:49
            +1

            Поддержка кодировок из коробки — рука лицо, неужели так сложно сделать конвертацию разных кодировок из коробки, и да поддерживаю все что сказано вышел про сеть, строки, я бы ещё рефлекшен попросил( вполне устроили бы флаги компилятора) и аналог protobuff/Thrift, локализацию, стандартные либы типа zlib, libpng, libjpg из коробки, xml парсеры, математические типы, хотябы float3, matrix4x4, quaternion и операции с ними. Мультиметоды ещё хочу, пусть медленные ну да и черт со скоростью.
            Берешь графический движок, в нем Vector3, берешь физически движок в нет Point3, берешь звуковой в нем float3, берешь либу с поиском пути в ней Float3 и сидишь пишешь бесконечные конвертации точек и матриц из одной либы в другую, со строками такая же бида.


            1. TargetSan
              14.07.2016 00:56
              +10

              Cargo. Просто Cargo. И все эти 3 либы будут использовать один набор типов из крейта 3d-geometry.


              Упс, мы же про С++. Нет, не судьба.


            1. Qbit
              19.07.2016 14:52

              > Берешь графический движок, в нем Vector3, берешь физически движок в нет Point3

              Строго говоря, Vector и Point — это разные типы данных (даже если одинаковые структуры данных).


          1. VoidEx
            14.07.2016 01:52
            +2

            > посимвольно

            по-code-point-но вы имеете в виду?


            1. khim
              14.07.2016 02:41
              +6

              Я думаю он имеет в виду «шоб с русским работало, а все немцы и турки идут в жопу».

              Но это мысли — интересно в какие слова они облекутся.


              1. webkumo
                14.07.2016 11:20

                Та же Java умеет и так и так. Хочешь — итерируешься по символам (кодпоинты идут… далеко идут), хочешь — по кодпоинтам. В чём трабла сделать аналогично в c++?

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


                1. khim
                  14.07.2016 13:28
                  +3

                  PS просто не всегда нужно умляуты и прочие радости учитывать при обходе строки (например, если ищешь цифры — то они никакого значения не имеют).
                  Если ищешь цифры (парсишь XML или там JSON), то достаточно работать с байтами если у тебя UTF-8.


                  1. webkumo
                    14.07.2016 13:47

                    Цифры — лишь пример. Вопрос в том, что умляуты и прочие код-поинты, не учитывающиеся как символ для некоторого класса задач не имеют значения. Да и кодировка может быть не одно-четырёх-байтовая UTF-8, а двубайтовый UTF-16.

                    PS под возможной кодировкой я подразумеваю, что для хранения данных в типе строки кодировка (по уму) должна быть одна, но её можно выбирать из разных кодировок, в то же время я знаю две универсальные кодировки — UTF-8 и UTF-16.


                    1. DistortNeo
                      14.07.2016 14:31
                      +1

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

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

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


                      1. gecube
                        17.07.2016 13:24

                        Микроконтроллер и С++ 17-года? Ну-ны.
                        Мне кажется, что все-таки в МК используют либо свой диалект Си, либо некое подмножество современного С++.
                        Но то что язык идет в тупик — это факт.
                        (С++ реально крутой, но каждая итерация нового стандарта делает его все монструознее и монструознее)


                        1. Falstaff
                          17.07.2016 13:55
                          +3

                          Проблема в том, что никто не будет писать компилятор именно для какого-то подмножества, да и кто его будет стандартизировать. Поэтому я согласен с DistortNeo в том что раздутая стандартная библиотека имеет минусы — на маленьких контроллерах используется тот же компилятор и тот же язык (разве что системные вызовы из libc и иже с ним по необходимости приходится самостоятельно делать), и C++ там тоже очень полезно использовать, но по мере роста библиотеки, во-первых, будет усложняться портирование, а во-вторых будут учащаться случаи, когда хочется использовать вполне скромный стандартный класс, а он за собой дёрнет iostream — бабах, плюс двести килобайт кода, а на контроллере всего сто двадцать восемь. Языку очень-очень нужны модули и что-то вроде пакетного менеджера, вроде того что у Rust — лучше сподвигнуть людей писать больше лёгких в использовании библиотек, чем засовывать в комплект ещё больше батареек.


                          1. khim
                            17.07.2016 23:26
                            +2

                            Языку очень-очень нужны модули и что-то вроде пакетного менеджера, вроде того что у Rust — лучше сподвигнуть людей писать больше лёгких в использовании библиотек, чем засовывать в комплект ещё больше батареек.
                            «Батарейки в комплекте» — штука тоже хорошая, но тут у C++ тоже огромная засада: так как каждый тянет одеяло на себя, то в результате в стандарте — очень странная комбинация из вещей, которые мало кому нужны (но зато против которых никто не возражал) и полнейшее отсуствие вещей, которые всем нужны, но про которые каждый хочет чего-то своего.

                            Простейший пример: ни запустить подпроцесс, ни разобрать параметры, пришедшие в main (с выделеним обязательных/необязательных параметров, etc) средствами стандартной бибилиотки нельзя. Разработчикам систем для микроконтроллеров это, в общем-то и не нужно — но зато нужно всем остальным!


                            1. Antervis
                              18.07.2016 05:30

                              std::system запускает подпроцесс. А разбирать параметры, пришедшие в main, можно далеко не единственным способом (как минимум, синтаксис параметров в винде и линуксах разный). И пусть лучше этот парсинг остается в виде отдельных либ, типа boost::program_options


                              1. khim
                                18.07.2016 16:29
                                +5

                                std::system запускает подпроцесс.
                                Лучше бы он его не запускал. Количество дыр в безопасности, которые образовались из-за того, что в стандарте есть только std::system — не счесть.

                                Но да, запускает, тут вы правы.

                                А разбирать параметры, пришедшие в main, можно далеко не единственным способом (как минимум, синтаксис параметров в винде и линуксах разный).
                                С одной стороны — вы правы: для создания переносимых программ какой-нибудь getopt не годится.

                                С другой — это значит что сотни тысяч программистов пишут сотни тысяч велосипедов при написании простейших утилит (потому что требование «использовать только стандартуную библиотеку» у заказчиков встречается частенько). Зачем? Ради чего вся эта бурная деятельность?


                                1. Antervis
                                  18.07.2016 17:59
                                  +1

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


                                  1. khim
                                    18.07.2016 18:41
                                    +5

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

                                    Я прекрасно понимаю почему члены комитета не могут решить эту проблему — но это не меняет того факта, что конечный результат (огромный и очень сложный язык, который, тем не менее «из коробки» не умеет «элементарных вещей») — очень неприятен.


                                1. 0xd34df00d
                                  20.07.2016 01:18
                                  +2

                                  потому что требование «использовать только стандартуную библиотеку» у заказчиков встречается частенько

                                  Я бы на месте этих программистов старался избегать таких заказчиков с такими немотивированными требованиями.


                                  1. khim
                                    20.07.2016 17:58
                                    +2

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

                                    Никогда не пробовали объединять код, написанный даже не на основе разных библиотек, а на основе всего-навсего всем известного boot'а? Когда один компонент хочет версию 1.20, а другой 1.50… подружить их бывает ох как непросто.


                                    1. 0xd34df00d
                                      21.07.2016 21:43
                                      +1

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

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

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


                        1. 0xd34df00d
                          18.07.2016 04:35
                          +4

                          Микроконтроллер и С++ 17-года? Ну-ны.

                          gcc вроде до сих пор всякие там atmega и прочие attiny поддерживает, разве нет?


                    1. khim
                      14.07.2016 14:52
                      +3

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

                      PS под возможной кодировкой я подразумеваю, что для хранения данных в типе строки кодировка (по уму) должна быть одна, но её можно выбирать из разных кодировок, в то же время я знаю две универсальные кодировки — UTF-8 и UTF-16.
                      И опять-таки дихотомия неправильная. Есть два класса кодировок:
                      1. UTF-8 — кодировка с которой просто работать и расширять языки не нужно
                      2. Всё остальные кодировки — работать с которыми сложно и потому расширять язык тоже не нужно

                      UTF-16 относится ко второму классу. UCS-2 (из-за которой в некоторых языках и операционных системах и появилось угробище под названием UTF-16) — да, была проста и красива. Хотя платила за это наличием своих собственных недостатков. UTF-16, увы, имеет все недостатки UTF-8 (один кодпоинт и один элемент строки — разные вещи), но также унаследовала все недостатки USC-2 (например бывает UTF-16LE и UTF-16BE, а это значит что вам нужен BOM и вам нужно знать есть у вас BOM или нет и т.д. и т.п.)

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


                      1. mayorovp
                        14.07.2016 16:58

                        Вообще-то, в UTF-8 тоже есть BOM...


                        1. stack_trace
                          14.07.2016 17:00

                          Гм, можно ссылку? И объяснение, зачем он нужен, заодно?


                          1. mayorovp
                            14.07.2016 17:11

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


                            Но в том же C# любой текстовый файл, записанный в кодировке UTF-8 по умолчанию будет иметь BOM.


                            1. stack_trace
                              14.07.2016 17:14
                              +1

                              Просто BOM — по определению Byte Order Marker. В UTF-8 никакого byte order нет и быть не может, так как единица анализа в нём — один байт. Возможно, очередное гениальное решение Майкрософта?


                              1. RPG18
                                14.07.2016 17:32
                                +2

                                1. stack_trace
                                  14.07.2016 22:19
                                  +1

                                  Это размер код поинта, а единица анализа — один байт, и следуют он точно один за другим в одном порядке на любой архитектуре. Проще говоря, парсится UTF-8 побайтово, в отличие от того же UTF-16.


                              1. khim
                                14.07.2016 18:52

                                Именно так. Майкрософт решил его использовать как маркет UTF-8 файла. Но это уже самодеятельность — мало что что ещё можно придумать чтобы жизнь себе усложнить.


                    1. lorc
                      14.07.2016 18:28
                      +2

                      Вообще UTF-16 не двубайтовая. Не путайте её c UCS2.


            1. VioletGiraffe
              14.07.2016 07:51
              +3

              Да, именно так. Чтоб была какая-нибудь функция length, которая возвращает количество code points, и какой-нибудь operator[], который возвращает собственно code point.


              1. khim
                14.07.2016 13:29
                +2

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


          1. khim
            14.07.2016 02:40

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

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

            P.S. Так, навскидку: не забываем что upcase("?") == «SS», что upcase(«i») ==«I» у большинства народов, но турков upcase(«i») == "I" и т.д. и т.п.


            1. VioletGiraffe
              14.07.2016 08:06

              Это реально нужно в любой задаче, где нужно что угодно делать с не-ASCII текстом. Распарсить XML, например.


              1. VoidEx
                14.07.2016 09:08
                +3

                Зачем там кодпойнты? Чтобы найти '<', '>', '/', кавычки — про код-пойнты знать не надо, работы «как с ASCII» хватит, так как кусок кодпойнта принять за '<' невозможно. Чтобы понять, пробельный ли символ — тоже. Чтобы сравнить открывающий тег с закрывающим — тоже. Что я не учёл?


                1. Azoh
                  14.07.2016 11:44

                  Например того, что существуют многобайтные кодировки.


                  1. mayorovp
                    14.07.2016 12:52
                    +1

                    Вообще-то тут обсуждались строки в UTF-8, а не в произвольной кодировке.


                  1. khim
                    14.07.2016 14:56

                    Хватит фигнёй страдать, а? Вы мне реализуйте прототип строки с осмысленным operator[] для ISO-2022, а я посмеюсь. Только про эскейп-символы и связанные с ними радости не забудьте, пожалуйста.


                    1. Azoh
                      14.07.2016 15:23

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


                      1. khim
                        14.07.2016 18:58

                        Это то с чего началась данная ветка: дайте, типа, нам посимвольный доступ в UTF-8 строку.

                        На вопрос «зачем» ответа так и не последовало, хотя, я на 99% уверен в своей версии: «нам с русским языком работать не удобно, а о немцах, турках и японцах мы думать не хотим — пусть идут куда им захочется… хотят на три буквы, хотят — на пять или десять».

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


                        1. Azoh
                          15.07.2016 10:14
                          +1

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

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


                          1. khim
                            15.07.2016 20:45

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

                            И уже разработчик будет решать, что ему использовать.
                            Если бы всё было так просто. Проблема в том, что переход между «потоком байт» (ну, например, именем файла в Linux'е) и «текстом» (ну, например, сообщением «файл «...» имеет размер «...» байт») вовсе не так очевиден как хочется и кажется.

                            Нужны что-то более сложное — вот тебе полноценные строки, но за них придется платить памятью и скоростью.
                            А что будет если вы отнесёте что-то не в ту категорию? Программисты очень часто не задумывась, относят что-то не в ту категорию — и если у вас есть два жёстко разделённых мира, то исправление этой ошибки — очень дорого. Если у вас и то и другое — строки (подход C++, Go, Python2 и множества других языков) — то жить становится гораздо легче.

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


                        1. Idot
                          20.07.2016 14:26

                          Это то с чего началась данная ветка: дайте, типа, нам посимвольный доступ в UTF-8 строку. На вопрос «зачем» ответа так и не последовало, хотя, я на 99% уверен в своей версии: «нам с русским языком работать не удобно, а о немцах, турках и японцах мы думать не хотим — пусть идут куда им захочется… хотят на три буквы, хотят — на пять или десять».

                          А японцы, которых Вы упомянули, по-Вашему, что UTF-8 — не используют?!
                          Это необходимо всем у кого алфавит не на латинице, то есть как минимум 3 миллиардам человек = китайцы + индийцы + японцы + корейцы + таиландцы + пакистанцы + бангладешцы + арабы + и так далее… То есть даже без России — это половина человечества, если не больше, так как в Африке существуют алфавиты тоже основанные не на латинице.


                          1. Dionis_mgn
                            20.07.2016 14:56
                            +3

                            Человек убежден в том, что 99% страждущих посимвольный доступ к UTF-8 строкам хотят весьма кривую реализацию, которая будет отлично работать с кириллицей и не работать с иероглифами, немецким и турецким языками и т.п. Ибо эти 99% человек просто не сталкивались с этими проблемами, а потому не представляют, во что превратится нормальная поддержка UTF-8 в стандарте. И я с ним согласен, впихнуть UTF-8 в стандарт — это надо постараться. Да и кому оно ДЕЙСТВИТЕЛЬНО надо?
                            Я последние 3 года разрабатываю старый Web-проект с бэкендом на плюсах (+ свой проект тоже на плюсах). Ни разу не было реальной необходимости в посимвольном доступе к UTF-8 строкам.
                            В тех же случаях, когда сложная работа с UTF-8 действительно нужна, лучше просто взять специальную библиотеку, а не желать этого в стандарте языка.
                            Это примерно как желать 3D движок в стандарте C++. Но что-то я не вижу желающих интегрировать в стандарт, например, OGRE.


                            1. DistortNeo
                              20.07.2016 16:53
                              -3

                              Стоп. Давайте разделять UTF-8 и Unicode.

                              UTF-8 — это просто способ кодирования 31-битных значений в виде последовательности 8-битных байт. Он никак не привязан к смысловому содержанию этих значений.

                              Для подавляющего большинства практических задач обработки строк посимвольный доступ (=преобразование UTF8 в UCS2/UCS4 на лету) не нужен — можно работать напрямую с UTF8 представлением строки.

                              Если всё-таки нужен произвольный посимвольный доступ, то будет гораздо эффективнее преобразовать строку в массив 2-байтных или 4-байтных значений, а после работы преобразовать обратно. А если ещё хочется и менять значения символов на месте, то как вы себе это представляете для UTF8?


                            1. Idot
                              21.07.2016 07:17

                              Ну, работа с текстом требуется куда чаще, чем работа с 3D. Давно уже большая часть приложений не сводится к «продвинутому фортрану».


                1. VioletGiraffe
                  14.07.2016 13:39

                  Да, вы правы, если в строке интересны только ASCII символы — можно обойтись без понимая UTF-8 и Юникода вообще.
                  Но вот мне, например, недавно нужно было искать в тексте кавычки не только обычные, но и “/”, «/», а также символ троеточия.


                  1. khim
                    14.07.2016 14:43
                    +3

                    Символ троеточия ищется в UTF-8 как последовательность трёх байт 0xe2 0x80 0xa6 — для этого совершенно не нужны глубины глубин.

                    Только сначала прогоните текст один раз через фильтр, убедитесь что это корректный UTF-8…


            1. warlock13
              14.07.2016 11:43
              +2

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


              Или если вы пишете компилятор для языка программирования, поддерживающего юникодные спецсимволы (ну как в Mathematica и Haskell), то вам тоже понадобится посимвольный разбор.


              1. khim
                14.07.2016 14:37
                +2

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

                Или если вы пишете компилятор для языка программирования, поддерживающего юникодные спецсимволы (ну как в Mathematica и Haskell), то вам тоже понадобится посимвольный разбор.
                Зачем? Если вам достаточно «халтурной» реализации — посимвольной обработки хватит. А если вы хотите полноценную поддержку, то тут всё сложнее. Нужно как-то обрабатывать LTR, возможно придётся как-то озаботиться сравнением Hangul Syllables и Hangul Jamo и прочее.


                1. warlock13
                  15.07.2016 10:20

                  А ещё их может не быть — совсем. Как в Китайском и Японском, к примеру.

                  Не понял, чего нет в китайском и японском? Пробелов?


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

                  Ну в этой-то отдельной процедуре настоящие юникодные строки вам будут нужны, так ведь?


                  1. khim
                    15.07.2016 20:49
                    +1

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

                    Ну в этой-то отдельной процедуре настоящие юникодные строки вам будут нужны, так ведь?
                    Скорее нет, чем да. Оперировать с отдельными символами вам там нужно будет очень редко, вполне достаточно требования что на входе — корректная UTF-8 строка. Вот это — да, нужно чётко отделять уровни где у вас std::string — это ещё «поток байт» и уровни где это уже текст (==корректный UTF-8).


        1. mezastel
          13.07.2016 22:41
          -5

          Со строками например такая проблема: у строки есть и size() и length(). Вот представьте вы начинающий разработчик, хотите понять что это за функции такие? Интуиция как бы подсказывает, что length = количество буков (символов), а size = размер "сколько вешать в байтах". Но не тут-то было. К тому же, в упор непонятно, почему это length() — функция, а не свойство строки. Но это уже другая история.


          Про UTF-8 я вообще помалчиваю. Мне бы хоть ASCII но с вменяемым синтаксисом. Где split(), to_lower(), и прочие очевидные вещи? Почему я использую Boost на каждый чих? Ведь Boost — это глобальные функции, а это полная отсутствие discoverability, то есть, есть у вас IDE, нет ее, не важно, т.к. комплишн по всем глобальным символам еще-не-заимпортированных заголовков не сделать в принципе.


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


          Вообщем, проблем много.


          1. warlock13
            14.07.2016 02:27
            +16

            К тому же, в упор непонятно, почему это length() — функция, а не свойство строки.

            Потому что в C++ нет свойств? Или я что-то пропустил?


          1. JIghtuse
            14.07.2016 07:28
            +1

            "Стандартный" split должен быть эффективен и широко применим. Есть n3593 с довольно адекватной мотивацией. Ждёт как раз упоминаемых string_view и Ranges.


            1. stack_trace
              14.07.2016 17:00
              +3

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


              1. Videoman
                14.07.2016 17:44

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


        1. Idot
          14.07.2016 04:31
          -5

          30 лет не могут сделать нормальные строчки — поиск, замена, lower/upper/locale
          30 лет «ходим на костылях», а комитет грезит о дальнем космосе
          запилить строки, синхронизацию, работу с файлами и сетью (+ асинки) — закроет 95% потребностей программистов

          Точно вместо удовлетворения необходимостей, комитет занимается тем что блаженно чешет своё ЧСВ. :(

          PS создайте кто-нибудь петицию на Change.org чтобы до этих зажравшихся козлов в комитете наконец дошло!


          1. AlexP11223
            14.07.2016 10:28
            +3

            Лучше сразу на roi.ru


          1. stack_trace
            14.07.2016 16:55
            +2

            Почему не в спортлото?


      1. DistortNeo
        13.07.2016 23:16
        +1

        Модули — это основная причина, делающая крайне затруднительным использование стороннего кода и невозможным — менеджеров пакетов. Кстати, экспериментальная реализация модулей уже есть в Visual Studio 2015 Update 2. Но она настолько сырая, что пользоваться ею не хочется совсем.

        STL ужасен до невозможности после опыта работы с более новыми языками с нормальными библиотеками. Больше всего бесит широкое использование беззнаковых типов и смешение знаковых/беззнаковых. Затем — ужасный iostream с нелогичными перегрузками и форматированием. В качестве прикола пытался написать аналог .NET String на C++ с SubString (с указателями), особенно String.Format с variadic templates. Даже работало и было на порядок удобнее printf и тем более cout.


        1. DistortNeo
          13.07.2016 23:49

          Хм, имелось в виду «отсутствие модулей» — плохо.
          И я очень надеюсь, что с введением модулей будет полностью переработана STL.


          1. mezastel
            14.07.2016 00:24

            Я вот думаю, так под шумок модулей можно и STL переписать. Но это скорее мечты.


            1. Deosis
              14.07.2016 10:37
              +4

              Основная проблема в том, что одним из столпов С++ является обратная совместимость: если кто-то 10 лет назад использовал какую-либо функцию, то её уже не удалить из стандарта. А превращать язык в снежный ком никто не хочет.


              1. dpantele
                14.07.2016 18:08

                Есть же примеры такие как auto_ptr и не COW-строк в последних stdlibc++


                1. khim
                  14.07.2016 19:07

                  auto_ptr до сих пор поддерживается, а не COW-строки в GCC начали разрабатываться за много лет до появления стандарта (оказалось что COW-строки на многопроцессорных системах сильно медленнее, а экономия памяти редко когда стреляет).


                  Если вы не обнаружилось что из распространённых компиляторов только один использует COW-строки, да и тот планирует «при удобном случае» от них отказаться — фиг бы чего вышло. Да и то: это изменение старые программы не поломало, максимум — изменило потребление памяти.


                  1. dpantele
                    14.07.2016 19:19

                    И когда-то auto_ptr из стандарта совсем уберут, как убирают std::binary_function из c++17, то есть при указании -std=c++17 он не будет определён.

                    Реализацию, наверное, не template-функций убрать из библотеки будет сложно, но никто в приципе не мешает старым программам требовать старую stdlib.

                    А насчёт COW — это я имел ввиду то, что бинарную совместимость тоже иногда ломают.


                    1. khim
                      14.07.2016 23:16

                      А насчёт COW — это я имел ввиду то, что бинарную совместимость тоже иногда ломают.
                      А тут как раз очень забавно. У Microsoft'а она вообще ломается каждую версию, а в Linux'е введение не-COW строк, строго говоря, бинарную совместимость не сломало. Тeперь в стандартной библиотеке есть std::string и std::__cxx11:string — и, в теории, ничто не мешает библиотекам и программам продолжать поддерживать и использовать оба вида строк…


                      1. dpantele
                        14.07.2016 23:24

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

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

                        А сейчас нет чего-нибудь что требует страый gcc для сборки?


                        1. khim
                          15.07.2016 21:02

                          А сейчас нет чего-нибудь что требует страый gcc для сборки?
                          Старые программы испольщующие, скажем, iostream.h? Это, кажется, самое заметное несовместимое изменение…

                          Предыдущие «циклы» (переход с GCC 2.95 на GCC 3 и с GCC 3 на GCC 3.4+), кажется все уже и забыли…


                      1. phprus
                        15.07.2016 11:03

                        > а в Linux'е введение не-COW строк, строго говоря, бинарную совместимость не сломало.
                        Строго говоря как раз таки сломало.
                        Если разные модули будут использовать в своих API stl строки, и будут собраны в режиме С++11, но один компилятором GCC-4.*, а второй — GCC-5 и выше, то они будут ABI не совместимы.


                        1. khim
                          15.07.2016 20:52

                          Если разные модули будут использовать в своих API stl строки, и будут собраны в режиме С++11, но один компилятором GCC-4.*, а второй — GCC-5 и выше, то они будут ABI не совместимы.
                          Зависит от того — как именно вы используете GCC-5. Вы можете им собрать свою библиотеку с std::string, с std::__cxx11:string и даже с обоими вариантами одновременно.


                          1. phprus
                            15.07.2016 21:14
                            +2

                            > Зависит от того — как именно вы используете GCC-5
                            В общем случае нет, не зависит.
                            Собрать то свою библиотеку я действительно могу как угодно, но если какая-либо библиотека уже собрана (например, компонент без исходников) пусть в gcc-4.9, а в дистрибутиве линукса установлен gcc-5+ (с новым ABI по умолчанию), то эта библиотека будет не совместима с поставляемыми в дистрибутиве другими библиотеками (они то используют std::__cxx11:string вместо std::string).

                            По Вашей ссылке об этой проблеме тоже написано:
                            > If the third-party library cannot be rebuilt with the new ABI then you will need to recompile your code with the old ABI.
                            А «your code» вполне может быть и энное количество поставляемых в системе библиотек.
                            Какая же это совместимость ABI, если требуется «recompile your code with the old ABI»?


      1. encyclopedist
        14.07.2016 16:04
        +1

        В Clang модули реализованы уже несколько лет (правда не совсем тот вариант что пошёл в стандарт).


    1. iassasin
      13.07.2016 22:26

      Рад слышать! Тоже очень жду модулей!
      А где можно почитать «почти готовый» стандарт про них? Интересно, как он выглядит на данный момент.


      1. antoshkka
        13.07.2016 22:32
        +1

        В публичном доступе находятся не самые свежие версии, но разница с последними ревизиями незначительна:
        http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0142r0.pdf
        http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0143r2.pdf


  1. NeoCode
    13.07.2016 20:09
    +5

    Мне все интересно! Пишите больше, это очень интересная тема.
    Некоторые мысли по статье
    1. Как «if (init; condition)» будет взаимодействовать с объявлением переменных внутри круглых скобок if, т.е. «if(int x = foo())»?
    Кстати, сама по себе форма уже очень близка вот к этому https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html, т.е. к тому чтобы сделать стейтменты выражениями, как в Scala или Nemerle.
    2. Structured bindings… получается очень забавно — в С++ со всех сторон подошли к прямой реализации кортежей средствами языка, но видимо из-за «legacy» синтаксических особенностей так и не сделают. А так почти все есть — и списки инициализации, и pair/tuple, и вот теперь structured bindings…


    1. antoshkka
      13.07.2016 20:16

      1. Как «if (init; condition)» будет взаимодействовать с объявлением переменных внутри круглых скобок if, т.е. «if(int x = foo())»?

      Если нет `;` в `if`, то считается что в круглых скобках condition. Другими словами — работать будет так же, как сейчас.

      2. Structured bindings… получается очень забавно — в С++ со всех сторон подошли к прямой реализации кортежей средствами языка, но видимо из-за «legacy» синтаксических особенностей так и не сделают. А так почти все есть — и списки инициализации, и pair/tuple, и вот теперь structured bindings…

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


      1. NeoCode
        13.07.2016 20:44

        А если я там напишу более двух стейтментов? if( foo(); bar(); baz(); condition )
        Интересны пределы возможностей, так как реально это очень похоже на возможность использования цепочки стейтментов в выражении.
        Кстати, «if constexpr» это небось из D «static if» таки протащили?


        1. mezastel
          13.07.2016 22:01
          +1

          Ну не удивительно, т.к. Александреску позиционировал static if как основное преимущество D.


          1. gecube
            17.07.2016 13:33

            static if кроме как для шаблонов где-то нужен?


            1. mezastel
              17.07.2016 13:36

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


            1. Antervis
              17.07.2016 13:56
              +1

              Компилятор выкинет тождественные if'ы даже если они не помечены как constexpr. Суть в том, чтобы подавленная ветка даже не компилировалась.


      1. abikineev
        14.07.2016 14:52
        +2

        Тем самым возможно иметь два различных объявления внутри if стэйтмента:

        if (int x = foo();  double y = bar());
        

        А также вместо инит стэймента может быть экспрешн стэйтмент:
        if (do_something(); int x = foo());
        

        Кстати, кланг уже поддерживает эту фичу (спасибо мне и Ричарду Смиту :)


        1. dpantele
          14.07.2016 19:21

          А expression-statement — это для lock-guards, или для чего-то ещё?


  1. stepanp
    13.07.2016 21:15
    +3

    Видимо в бусте закончились фичи которые можно спереть в стандарт.


    1. antoshkka
      13.07.2016 22:00
      +1

      Фичей ещё очень много :)
      Просто комитет не занят стандартизацией только библиотек Boost.


      1. stepanp
        13.07.2016 22:12
        +11

        Непонятно чем он вообще занят. Импортов нет, концептов нет, filesystem нет. Даже pragma once(или ее аналог) не могут в язык внести.


        1. encyclopedist
          14.07.2016 02:42
          +4

          filesystem вообще-то есть.


        1. stack_trace
          14.07.2016 16:53
          +2

          Даже pragma once(или ее аналог) не могут в язык внести.

          Может, потому что эту «фичу» невозможно корректно имплементировать? Уже сто раз оговорено, что pragma once не должна использоваться в нормальном коде.


          1. DarkEld3r
            14.07.2016 16:57

            Можно ещё раз для тех, кто всё пропустил? Хотя бы ссылку. Потому что у нас pragma once используется и не вызывает никаких проблем, а кодовая база собирается разными компиляторами.


            1. stack_trace
              14.07.2016 17:06
              +2

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


              1. mayorovp
                14.07.2016 17:17
                +1

                У систем сборки (того же make, к примеру) есть точно такая же проблема — они не могут различать артефакты (цели) по символическим ссылкам в общем случае.


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


                И с pragma once то же самое.


                1. khim
                  14.07.2016 19:09
                  +1

                  И с pragma once то же самое.
                  Нет, не то же самое. Систем сборки не страдающих от указанных вами проблем я не видел (для языков без модулей, в общем-то, и альтернатив не придумать), а для pragma once альтернатива есть, описана в стандарте и работает ничуть не хуже.


                  1. ozkriff
                    15.07.2016 08:53

                    Систем сборки не страдающих от указанных вами проблем я не видел

                    Хм, вроде как SCons по умолчанию использует md5 по содержимому файла для определения его уникальности. Вроде это должно помочь при сложностях со ссылками.


                    1. khim
                      15.07.2016 21:08

                      Хм, вроде как SCons по умолчанию использует md5 по содержимому файла для определения его уникальности.
                      Если бы SCons этим занимался, то он бы обрабатывал мало-мальски сложные проекты невменяемо долго. MD5 Scons использует, но уже после проверок на изменение даты. Если файл изменится, а дата модификации и размер останутся неизменными — SCons ничего не заметит…

                      Всё просто: посмотреть на метаинформацию можно даже если у вас в проекте сотни тысяч файлов. А делать что-то другое — слишком накладно если у вас исходников достаточно много.


                      1. ozkriff
                        15.07.2016 22:12
                        +1

                        Если бы SCons этим занимался, то он бы обрабатывал мало-мальски сложные проекты невменяемо долго

                        Это очень похоже на мое о нем впечатление)


                        Смотрю в доках:


                        By default, SCons keeps track of whether a file has changed based on an MD5 checksum of the file's contents, not the file's modification time.

                        И судя по тем же докам, проверка времени изменения перед проверкой хешей опциональна и требует явного включения — Decider('MD5-timestamp').


              1. DarkEld3r
                14.07.2016 17:19

                Спасибо.


                Из любопытства заглянул в исходники Clang: там и правда инклюд гарды используются. Тем не менее, все популярные компиляторы эту прагму поддерживают ведь. И я как-то не встречал рекомендаций от неё отказываться. Если она такая проблемная и это "общепризнанно", то могли бы хотя бы предупреждение выдавать.


                1. Jebediah_Kerman
                  14.07.2016 18:08

                  GCC первоначально выдавал предупреждение об отключении pragma once, если компилируемый код использовал её. Тем не менее, в релизе 3.4 GCC код обработки команды pragma once был исправлен для корректной работы с символьными и жёсткими ссылками. Данная возможность была сочтена полезной и предупреждение было убрано
                  https://ru.wikipedia.org/wiki/Pragma_once


                  1. DarkEld3r
                    14.07.2016 20:20
                    +2

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


                    1. stack_trace
                      14.07.2016 22:29
                      +4

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


                      1. DarkEld3r
                        15.07.2016 10:46
                        +1

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


                        1. stack_trace
                          15.07.2016 11:15

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


                          1. DarkEld3r
                            15.07.2016 11:37
                            +4

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


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


                            1. khim
                              15.07.2016 21:15
                              -1

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

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


                              1. mayorovp
                                15.07.2016 22:28
                                +2

                                При использовании одномённых гардов компилятор ошибку, конечно, выдаст — но найти ее причину будет не проще чем найти #define true false. Потому что компилятор попросту не включит один из двух конфликтующих заголовочный файлов — и потом выдаст кучу воплей о необъявленных типах и функциях.


                                1. 0xd34df00d
                                  16.07.2016 20:18
                                  +2

                                  Да. И с такими проблемами «в продакшене» я сталкивался, особенно при рефакторинге. С проблемами с прагмами я не сталкивался ни разу.


              1. Bronx
                15.07.2016 07:16

                Почему бы тогда не позволить #pragma once(MY_HEADER), которая была бы «сахаром» для

                #ifndef MY_HEADER_#FILEHASH#
                #define MY_HEADER_#FILEHASH#

                #endif?


                1. khim
                  15.07.2016 21:20

                  Потому что это решение — хуже существующего. Например потому что существующее решение не зависит от хеша файла.

                  P.S. Когда может оказаться полезным трактовать разные файлы как одинаковые? Когда это — разные версии одного и того же файла.

                  P.P.S. Я не говорю что существующее решение — идеально. Но так как все «простые решения» имеют свои подводные камни, то лучше не пытаться забить очередной костыль (который всего лишь заменит одну проблему другой), а всё-таки подумать на тему модулей. Ну не создают нормальные люди новые файлы так часто, чтобы эти три строчки были проблемой, не создают!


                  1. DistortNeo
                    15.07.2016 23:18
                    -1

                    Генерите уникальный GUID на каждый новый файл. Всё, проблемы больше нет.


                    1. Mingun
                      16.07.2016 00:20
                      +1

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


  1. TargetSan
    13.07.2016 21:40
    +2

    inline для переменных — если в разных единицах трансляции присутствует переменная с внешней линковкой с одним и тем же именем, то оставить и использовать только одну переменную (без inline будет ошибка линковки);


    Извините, но это капитальнейшая подстава и здоровенная пуха, которая теперь будет отстреливать ноги всем и по самую шею!


    1. zelyony
      13.07.2016 21:46
      +1

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


      1. TargetSan
        13.07.2016 21:55
        +1

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


    1. Antervis
      14.07.2016 06:15

      Чтобы так «пальнуться» надо написать что-то типа inline int a = ...; в двух .cpp вне классов/методов/неймспейсов. Нечаянно взломать сейф, так сказать


      1. TargetSan
        14.07.2016 09:05

        Не-а. Надо как раз забыть у статик-переменной дописать static, который сделает ей локальную видимость.


  1. TargetSan
    13.07.2016 21:46
    +1

    std::string_view

    std::array_view я так понимаю не будет?


    1. antoshkka
      13.07.2016 22:04

      В C++17 не будет, но есть надежда что скоро появится в std::experimental::


    1. mezastel
      14.07.2016 00:26
      -1

      Тут кстати интересная дуальность. Везде в STL у нас обобщенные алгоритмы которые берут begin()/end() не важно откуда. А для строк почему-то свой string_view хотя по логике вещей могли бы дать и array_view и сказать "а дальше вы сами". Ведь по сути, пока нет поддержки юникода, строки и массивы — это одно и то же :)


      1. TargetSan
        14.07.2016 00:43
        +3

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


        Ну и наконец, моё сугубо личное мнение, что сама по себе идея делать 2 итератора на диапазон, да ещё и требовать от них совместимости по интерфейсу с указателями, была отвратительной. Потому что реально в случае с RandomAccessIterator, например, у нас не 2 итератора, а слайс — убого скрытый под 2-мя итераторами. А теперь городим костыли в виде разнотипных итераторов. И, кстати, в stdlib до сих пор нет шаблонов для конструирования этих самых итераторов.


        1. mezastel
          14.07.2016 00:48

          Ну, если на то пошло, давайте признаемся что в современном мире более рационально сделать некий интерфейс IEnumerable<T> (привет C#) и поддержать ключевое слово yield, которое дает возможность произвольно возвращать коллекцию даже тогда, когда это дерево и нужна рекурсия. В С++ сейчас писать итератор для дерева в рекурсивном стиле невозможно.


          А потом можно передавать не begin()/end() а просто сам объект. И все счастливы.


          1. TargetSan
            14.07.2016 01:00
            +8

            Примерно так и есть. Сделано, кстати, в одном языке на R, 4 буквы в названии. Ооочень удобно, даже без yield — когда итерирование по коллекции — 1 метод, а не как минимум 3-4.


            1. TheIseAse
              14.07.2016 09:48
              +3

              Что за язык? Ravascript? Rwift? Rython? Не томите!


              1. TargetSan
                14.07.2016 09:56
                +2

                Rust вообще-то. Почитайте на досуге, если интресно. Там, в частности, исправлены многие косяки С++.


                1. TargetSan
                  14.07.2016 11:17
                  +1

                  А можно от несогласных пояснение, где я не прав? Или в споре о С++ другие языки и, в частности, потенциальных конкурентов, упоминать запрещено?


                  1. DarkEld3r
                    14.07.2016 15:06

                    Ну… евангелизм бывает навязчивым. (:


                    Если что, мне самому раст очень интересен, так что минусов не ставил, даже наоборот.


                    1. khim
                      14.07.2016 15:10
                      +2

                      Потерпите пару годков. Go тоже несколько лет назад усиленно PRили. Потом успоколились. Сейчас вот Swift и Rust.

                      P.S. Swift меня не волнует от слова никак — точно так же, как не волнует, скажем, язык 1С (зачем мне язык намертво завязанный на чужую экосистему?), а на Rust — я поглядываю, но пока не решился ничего серьёзного на нём писать.


                      1. DarkEld3r
                        14.07.2016 15:30
                        +1

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


                    1. TargetSan
                      14.07.2016 15:26
                      +2

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


        1. Antervis
          14.07.2016 11:29

          есть функция std::distance, который как раз выдаст длину контейнера, определяемого итераторами begin и end. Точно так же у большинства контейнеров определен конструктор, принимающий итераторы и возвращающий, по факту, подмассив указанного размера: std::wstring ws = L«sometext»; std::string s(ws.begin()+4, ws.end()); вернет «text»


          1. TargetSan
            14.07.2016 11:44
            +1

            Проблема в том, что в общем случае очень трудно определить, какая категория итераторов пришла. Да просто нет возможности поставить ограничение «здесь принимается random access iterator».
            Плюс, ограничение на тип элемента делается криво.
            Плюс, функции, принимающие итератор, обязаны быть шаблонными — а принимающие срез конкретного типа — нет.

            В общем, пользоваться можно — но срезы удобней.


            1. Antervis
              14.07.2016 12:58
              +1

              Почему же трудно то?
              template std::enable_if_t<std::is_same<std::random_access_iterator_tag, typename T::iterator_category>::value,void>
              doSomething(T begin, T end) { /*...*/ }
              Вот вам и ограничение «здесь принимается random access iterator».

              Шаблонность в общем случае тоже необязательно — можно пользоваться auto функциями/лямбдами


              1. TargetSan
                14.07.2016 13:31
                +2

                Сравните с


                void doSomething(stdext::slice<int> someslice) { ... }

                1. Нет enable_if_t. Который в большинстве случаев применяется как костыль в отсутствии концептов
                2. Нет шаблонности — можно имплементацию прятать в другой модуль.
                3. Банально легче читать


                1. Antervis
                  14.07.2016 13:54

                  я доказывал только реализуемость


                  1. TargetSan
                    14.07.2016 14:22

                    Так я тоже писал, что возможно — но неудобно.


  1. TargetSan
    13.07.2016 21:48
    +2

    std::variant

    Они таки вставили null state. Не очень хорошо, честно говоря. Я так понимаю, это жертва для обеспечения exception safety. Хотя могли бы потребовать noexcept для деструкторов и move конструкторов.


    1. antoshkka
      13.07.2016 22:14

      Они таки вставили null state.

      Да, он называется valueless_by_exception() и возникает крайне редко.

      Хотя могли бы потребовать noexcept для деструкторов и move конструкторов.

      Есть много вариантов как реализовать std::variant, у всех есть свои недостатки. Мне нравилась версия «требовать noexcept default constructor для хотябы одного типа». Но у этой версии большие проблемы с юзабилити, так что std::variant с valueless_by_exception() намного более юзабельный.


      1. TargetSan
        13.07.2016 22:45

        Не в курсе, к сожалению. Реализовывал свой велосипедик на эту тему, чтобы работал на GCC 4.9 и не аллоцировал память. В результате пришёл к двум ограничениям — noexcept destructor и noexcept move constructor. На их основе можно делать variant который или будет всегда в валидном состоянии, или уронит программу std::terminate. Оба ограничения как по мне вполне адекватные. Кидаться исключениями из деструктора нехорошо, а из мув-конструктора — просто глупо. Кстати, noexcept default ctor в таком случае не нужен.


        1. encyclopedist
          14.07.2016 02:46
          +1

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


          1. TargetSan
            14.07.2016 09:06
            +3

            Вот кстати не могу представить throwing move. Подкинете пример?


            1. antoshkka
              14.07.2016 14:43

              Например один из вспомогательных компонентов boost::variant имеет потенциальный throwing move.


              1. TargetSan
                14.07.2016 14:57
                +1

                По-моему, аллокация памяти там сильно лишняя. Почему не могут просто отдать буфер? Ведь, по сути, recursive_wrapper почти то же самое, что и unique_ptr.


                1. antoshkka
                  14.07.2016 15:22

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

                  Если разрешить ему хранить nullptr и кидать исключение при разименоввывании (а его разименоввывание происходит внутри variant и скрыто от пользователя), то variant теряет never-empty guarantee и иногда начинает хранить пустой recursive_wrapper. В итоге получается нечто среднее между boost::variant и std::variant, чего всячески хочется избежать.


  1. Falstaff
    13.07.2016 21:54
    +1

    Комбинация structured bindings и if (init; condition) очень вкусно смотрится:

    if (auto [x, y] = foo(); y == something) {… }

    Как я понимаю, переменные, объявленные в секции init, существуют и внутри else тоже?


    1. antoshkka
      13.07.2016 22:17
      +3

      Да, внутри else тоже существуют. А ещё эта конструкция применима и к switch:

      switch (auto [x, y] = foo(); y) {
      case 1: x += 10; break;
      // ....
      default: x = 0;
      }
      


      1. kemm
        14.07.2016 12:25
        +1

        Хм… А до такого когда-нибудь доведут, интересно:
        switch (foo()) {
        case [true, result]:
        do_something(result);
        break;
        case [false, _]:
        LOG(error)


      1. kemm
        14.07.2016 12:46
        +3

        Хм… А до такого когда-нибудь доведут, интересно:

        switch (foo()) {
        case [true, result]:
            do_something(result);
            break;
        case [false, _]:
            LOG(error) << "Shit happens!";
            break;
        }


        Кстати, а плейсхолдеры добавили? Желательно что-нибудь минималистичное вроде того же "_", а не «std::structured_bindings::paceholders» 8)) И алиасы нподобие хаскеллевского «pair@(first, second)»? Понятно, что это сахарок, но без него таки не так сладко будет.

        PS: прошу прощения, в прошлом комментарии что-то с форматированием стряслось…


        1. Antervis
          14.07.2016 16:17
          +1

          так можно же писать using std::placeholders;


          1. kemm
            15.07.2016 14:38

            Ну тогда уж using _ = std::unused. И, к слову сказать, ещё вот какую-нибудь такую штуку было бы приятно иметь a-la designated inits:

            auto [st_size: sz, st_mode: mode] = fstat_wrapper(fd);
            if (S_ISREG(mode) && sz > 0xfffffffful)
                std::cerr << "Ooops.\n";
            


    1. jk057
      15.07.2016 17:23

      А теперь хочется чего-то вроде

      if ( auto [x, y, z] = [foo(), bar(), baz()]; y == something ) { }
      


      1. encyclopedist
        15.07.2016 17:31
        +2

        Так уже можно, используя std::tuple и новую возможность вывода аргументов шаблонов для классов:


            if ( auto [x, y, z] = std::tuple(foo(), bar(), baz()); y == something ) { }


  1. iyemelyanov
    13.07.2016 21:54
    +7

    Очень интересно влияет ли развитие Rust на идеи участников комитета и обсуждается ли он? Да и вообще очень волнительно как один из любимых языков будет развиваться когда рядом есть такой конкурент как Rust, да еще учитывая новости о том, что его начали использовать в Dropbox, переписывать на нем отдельные части в Firefox и т.д. Просто раньше как то все было проще и понятней, был C и С++, и практически подавляющее большинство задач системного программирования решалось на них, но теперь то все эти задачи можно точно так же решать и на Rust с его вроде как передовыми идеями, и что дальше?


    1. ababo
      13.07.2016 22:14
      +19

      Безобразное усложнение С++ волей-неволей заставляет смотреть в сторону Rust.


    1. mezastel
      13.07.2016 22:16
      +2

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


    1. stepanp
      13.07.2016 22:19
      +2

      Думаю к моменту выхода C++20 никакой С++ будет уже не нужен.


      1. VioletGiraffe
        13.07.2016 22:29
        +9

        С тем же успехом можно сказать, что к моменту выхода С++20 уже никакой Rust будет не нужен.


      1. Antervis
        14.07.2016 06:30
        +5

        Шел 2196-й год… С++ праздновал свой двухсотый день рождения новым стандартом, а его всё хоронили и хоронили…


        1. Error1024
          14.07.2016 09:09
          +2

          Как дельфист: добро пожаловать!


          1. snuk182
            14.07.2016 10:38
            -2

            это уже впору называть каким-нибудь «синдромом флешплеера» — его убивают, а он все чето никак.
            а Rust не будет конкурентом плюсам, пока к нему не будут разжеваны и задокументированы все шаблоны проектирования, иначе два из трех интересующихся будут отпадать в борьбе с компилятором.


            1. OnYourLips
              14.07.2016 10:54
              +2

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

              Тот же флешплеер работает сейчас в лучшем случае на трети устройств.
              Не вижу у этих технологий каких-то перспектив.


            1. varanio
              14.07.2016 11:28
              +1

              ну, флешплеер всё-таки сдох


              1. snuk182
                14.07.2016 11:48
                +2

                сдох-не сдох, но Block Plugins пока отключать рано


        1. red75prim
          14.07.2016 12:16
          +7

          … новым двадцатитысячестраничным стандартом…


  1. dendron
    13.07.2016 23:41
    +7

    Что-то я уже не уверен что введение новых сущностей просто чтобы писать меньше строчек себя оправдывает.

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

    Впитывая в себя куски из boost'а стандарт становится такой же беспорядочной помойкой — безумно распухшей коллекцией «прикольных фишечек».


    1. TargetSan
      14.07.2016 00:25
      +9

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


    1. DarkEld3r
      14.07.2016 15:14
      +2

      Ну string_view как раз штука удобная и нужная, да и раньше ей пользоваться можно было, что я успешно и делал. А вот вещи типа "if (init; condition)" тоже настораживают. Может это, конечно, во мне консервативность говорит, но оно кажется далеко не самым частым частным случаем. Для сравнения for по диапазону из C++11 мне очень нравится, да и случай чуть ли не самый частый.


  1. Videoman
    13.07.2016 23:46
    +9

    Какой кошмар!!! (Я в положительном смысле :). Интересно, а комитет изучал вопрос, сколько людей в состоянии изучить современный С++ с нуля, а не практикуя его постепенно в течении 20 лет?
    Мне кажется, что пора уже заканчивать с этим и нужно садиться за написание книг, где подробно описывать как теперь все это использовать и самое главное, что не использовать из старых практик, пока они сами не забыли как правильно.


    1. mezastel
      14.07.2016 00:29

      Это, вообщем-то, основная проблема. Сейчас мы можем втянуть студентов в С++ только силой, т.к. добровольно никто на нем писать не будет — сядут за C# или Java, сделают свое приложение, начнут его продавать. А в C++ остались те кто, как я, слишком долго сидел в этой теме и имеет некоторые априорные знания о том как все было 10-15 лет назад, и как проэволюционировало.


      1. TargetSan
        14.07.2016 00:53
        +9

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


        1. mezastel
          14.07.2016 00:56
          +1

          Слушайте, я вот недавно в Сан Фран ходил на встречу SG14, и там один человек на полном серьезе предлагал встроить С++ package management в язык (!!!). Хотя на дворе 2016 год и идея внешнего описания зависимостей уже проработана и испробована в Cargo, NuGet и так далее. То есть даже в C++ Working Group есть люди которые далеки от понимания того, что творится в мире разработки.


          1. TargetSan
            14.07.2016 01:06
            +2

            Это, простите, капец. По-моему, это PL/1 v2 уже какой-то.
            Хотя, с другой стороны, заставить всех использовать единый формат пакетов и проектов можно только жёстко впилив его в стандарт. Но этого не будет никогда — потому что MS, Google, GCC team будут вечно тянуть одеяло на себя.


            /fanboy mode on
            Хочу только одну вещь. Поддержку в Rust'е импорт C headers из коробки. После этого "два крестика" покатится cо всё нарастающей скоростью.


            1. ozkriff
              14.07.2016 13:03
              +3

              Хочу только одну вещь. Поддержку в Rust'е импорт C headers из коробки.

              Мне кажется, усложнять язык для этого нет нужны, лучше доработать bindgen: https://github.com/crabtw/rust-bindgen#plugin


              1. TargetSan
                14.07.2016 13:27
                +1

                Там ЕМНИП самая большая проблема осталась — макро константы. Но не будем здесь разводить оффтоп.


          1. sborisov
            14.07.2016 14:23
            +2

            Когда Степанов выступал в «Яндексе» (видео доступно), он рассказывал про комитет, и говорил, что там очень много людей, которые просто за счёт компании едут посмотреть на Париж и другие места, где проходят заседания комитета. Дословно было сказано: "У них нет знаний, но зато есть мнение.", а работа комитета устроена так, что каждое предложение, нужно изучить и аргументированно утвердить или отказать, т.ч. бюрократия сильно мешает.


  1. XaLBa
    14.07.2016 01:47

    Так а что с ranges?


    1. antoshkka
      14.07.2016 14:49
      +1

      Они зависят от концептов. Сначала примут концепты, потом рейнджи. Когда примут концепты, и примут ли их — не известно.


      1. Sliver
        20.07.2016 03:45
        +1

        А как они зависят? На обычных шаблонах, кажется, без проблем делается.
        Таскать везде begin и end вместо одного range — неудобно.
        Тот же string view — это же, по сути, range, но почему-то только для строк?


        1. antoshkka
          20.07.2016 14:17

          Ranges это не только добавление пары перегруженых методов к алгоритмам. Это еще и очень тесная интеграция с концептами и переписывание большей части снатдартной библиотеки. Так например метод all_of в данный момент выглядит вот так:

          template<class InputIterator, class Predicate>
          bool all_of(InputIterator first, InputIterator last, Predicate pred);
          


          С Ranges он будет выглядеть вот так:

          template<InputIterator I, Sentinel<I> S, class Proj = identity,
              IndirectCallablePredicate<projected<I, Proj>> Pred>
          bool all_of(I first, S last, Pred pred, Proj proj = Proj{});
          
          template<InputRange Rng, class Proj = identity,
              IndirectCallablePredicate<projected<iterator_t<Rng>, Proj>> Pred>
          bool all_of(Rng&& rng, Pred pred, Proj proj = Proj{});
          


          Оценить масштаб изменений можно почитав proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4569.pdf


          1. Sliver
            21.07.2016 03:16

            А это как-то мешает сейчас ввести ranges как простой шаблон с begin и end, а потом (если это потом настанет) уже расширить его концептами?
            Переделок будет даже меньше, чем делают сейчас, например, с параллельными алгоритмами.


            1. JIghtuse
              21.07.2016 07:06

              Одна из особенностей Range — begin и end могут быть разными типами (в примере выше это можно увидеть). Без этой возможности реализация значительно усложняется. А при её наличии ломается совместимость с предыдущими версиями стандартной библиотеки.


  1. oYASo
    14.07.2016 04:00
    +18

    Я большой фанат C++, но когда я читаю очередной черновик стандарта, мне всегда вспоминается этот комикс:
    комикс про 4096 процессоров

    Да, есть хорошие и удобные фичи. Но дофига нужного до сих пор нет!

    Навскидку:
    1) нормальные, черт возьми, строки!
    2) модули
    3) полиморфные лямбды
    4) xml, json и прочая сериализация/десериализация из коробки
    5) в мире существует сеть, и пора бы уже о ней узнать!
    6) ну и еще кучу всего, ночью уже сложно вспоминать…


    1. 0xd34df00d
      14.07.2016 04:11
      +3

      Что вы называете полиморфными лямбдами? А что — нормальными строками?

      А вообще, а вообще… Лучше бы хорошую compile-time type information, чтобы можно было адекватно AST манипулировать, писать автоматический вывод той же сериализации хоть в json, хоть куда хочешь, и так далее.


      1. rzhikharevich
        14.07.2016 21:18

        Что касается строк, есть интересная статья на эту тему: https://mortoray.com/2013/11/27/the-string-type-is-broken/


    1. Sirikid
      14.07.2016 04:13

      Да начнется священная война! (В какую статью про C++ не зайду обязательно кто-нибудь напишет такой список.)


    1. Antervis
      14.07.2016 06:36
      +4

      А в каком контексте текущие лямбды не полиморфны?


    1. mapron
      14.07.2016 06:58

      1) работа со строками это грусть, но это скорее претензии к STL, а не к языку.
      2) ну все ждут и все хотят, но это такая глобальная тема, что комитет не хочет сделать какашку, от которой следующие 30-50 лет люди будут страдать.
      3) а сейчас что не так
      4) дайте рефлексию, и все это будет не нужно. А черновиков по рефлексии несколько уже есть.
      5) вот тут просто +100500. Хотя бы ip-сокеты/listener-ы стандартизировали.


      1. DancingOnWater
        14.07.2016 11:42

        Да, рефлексии очень не хватает


      1. monah_tuk
        14.07.2016 13:53

        5) тут можно много копий поломать. К примеру, проакторный Asio я бы не сильно хотел видеть в качестве реализации сети в стандарте. Плюс, говоря о сети, нужно думать и о эффективной работы, неблокирующем режиме и мультиплексировании… А вот тут некая система Windows выделяется своим IOCP (без спора — что эффективнее)...


      1. antoshkka
        14.07.2016 15:03
        +2

        Работа над сетью идёт, на данный момент самым жизнеспособным предложением является предложение на основе ASIO, но правиьно переработанное http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4575.pdf.

        Очень много интересов сошлось на этом proposal. Все хотят сеть, но у всех разные желания: производительность, отзывчивость, простота, сопрограммы, единый интерфес с многопоточностью/stl, расширяемость и т.д.

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


        1. mapron
          17.07.2016 09:44

          Спасибо большое за ссылку, очень интересно!


    1. marsianin
      14.07.2016 07:46
      +2

      Это, конечно, интересные фичи. Только зачем они в стандарте?


      1. Dudraug
        14.07.2016 14:36
        +3

        А где еще модулям и рефлексии быть?


        1. marsianin
          14.07.2016 20:05
          -3

          Без модулей и так неплохо. А кому нужна рефлексия, тот знает, где скачать Java.


          1. 0xd34df00d
            14.07.2016 22:28
            +2

            Рефлексия бывает и компил-тайм, отсылка к джаве не обязательна.


        1. Dudraug
          15.07.2016 11:45
          +1

          Без модулей плохо.


    1. Sliver
      20.07.2016 04:09
      +1

      6*) нормальная функциональная поддержка для контейнеров чтобы можно было писать:
      m.filter(...).map(...).reduce(...)
      (но мы знаем, что это невозможно, пока не будет ranges, а ranges каким-то образом завязаны на концепты)


      6**) Вдобавок к (непринятой в 17м стандарте) возможности вызывать метод класса как method(object, arg), добавить аналог this для аргументов из C#, когда один из аргументов для функции можно написать через точку слева, как будто это вызов метода: arg1.func(arg2). Это позволит писать функции для работы с объектами, избегая огорода из скобок.


      6***) Убрать неконсистентное требование того, что временные объекты обязаны быть константными — чтобы заработало вот такое: func(C()), где C() — временный объект, который принимается в функцию по неконстантной ссылке.
      Потому что сегодня приходится размазывать это на две строки:
      C c = C(); func(c);
      чему не видно никакого оправдания.


      1. antoshkka
        20.07.2016 14:27

        6**) Вдобавок к (непринятой в 17м стандарте) возможности вызывать метод класса как method(object, arg), добавить аналог this для аргументов из C#, когда один из аргументов для функции можно написать через точку слева, как будто это вызов метода: arg1.func(arg2).

        Этим занимаются Страуструп и Габриель Дос Райс, но предложению предстоит ещё несколько итераций доработки. Вот последний proposal на эту тему http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0416r0.pdf


  1. Antibiotic
    14.07.2016 07:46
    +2

    По поводу if (std::lock_guard lock(m); !container.empty())
    Не могу в данный момент проверить, но не должно ли if (std::lock_guard lock(m), !container.empty()) делать тоже самое уже сейчас?


    1. JIghtuse
      14.07.2016 08:17
      +3

      Делает, но вы не можете одновременно объявить переменную и проверить её на произвольное условие.
      Здесь подобное обсуждалось.


      1. abikineev
        14.07.2016 21:14
        +1

        В Вашем примере мьютекс захватывается и сразу освобождается перед сиквенс поинтом — оператором,
        В случае if (std::lock_guard lock(m); !container.empty()) lock живет в течение всего if стеймента


        1. DistortNeo
          15.07.2016 00:02

          Вот только такой if коварен. Если в for заменить точку с запятой на запятую, то будет ошибка, а если в новом if — будет оператор запятая.


          1. khim
            15.07.2016 02:46

            Не будет. Оператор запятая тут недопустим. Вы должны либо описать ровно одну переменную (C++14), либо поставить-таки точку с запятой.


        1. JIghtuse
          15.07.2016 05:59

          Да, действительно. Я заставил пример собраться, но о семантике не подумал.


  1. ittakir
    14.07.2016 08:16
    +7

    Шел 2016 год, а я так и не мог написать в программе std::optional; (ага, я в курсе что через пару лет заработает).
    Зато постоянно добавляют кучу адовой эзотерики. Если раньше я мог сказать, что знаю С++, то теперь уже точно нет.

    Интересно, помогает ли все это это языку? Если 10 лет назад на нем писали почти всё, то теперь он скатывается в нишевые направления — 3D движки, OpenCV, микроконтроллеры и немного десктопного Qt (сужу по заказам на UpWork).
    Лично для меня, как стандартный C++/STL был непригодным к использованию 10 лет назад, так он и остается до сих пор (Строки, работа с файлами, сеть, потоки и т.д.). Даже долбаное кросплатформенное приложение с нативным GUI интерфейсом невозможно создать (когда там графический интерфейс появился, в начале 90х?). Утешает только Qt.


    1. antoshkka
      14.07.2016 08:23
      +8

      Вы забыли про браузеры, современные игры, высоконагруженые сервера, оффисные пакеты, программы для 3d моделирования, потрошки Андроида.


      1. ittakir
        14.07.2016 09:19
        -8

        Браузеры, офисные пакеты, 3d моделирование и прочие десктоп-приложения вполне успешно пишутся на C# и Java.
        Игры тоже.
        Сервера гораздо проще не высоконагружать, а горизонтально отмасштабировать, купив железа. А написать на языке, в котором как минимум строки Юникод поддерживают, не говоря уже о встроенной поддержке БД и т.д.


        1. Tujh
          14.07.2016 09:26
          +8

          Просто в рамках самообразования, можно посмотреть на браузер целиком написанный на С# или Java? Ну и сервер, выдерживающий проблему C10k?


          1. ittakir
            14.07.2016 09:35
            -10

            Давайте говорить про доступные на рынке работы. Количество браузеров к общему количеству написанного ПО ничтожно мало. Я не знаю, на чем написаны конкретные браузеры, но не вижу большой проблемы написать их на C# или Java.
            Сервер с C10k есть прямо в статье https://en.wikipedia.org/wiki/C10k_problem это некий MigratoryData на Java на 10–12млн подключений.


            1. Tujh
              14.07.2016 09:53
              +7

              Как-то странно у нас диалог пошёл. Сперва Вы пишите:

              Браузеры… вполне успешно пишутся на C# и Java.

              затем:
              Я не знаю, на чем написаны конкретные браузеры, но не вижу большой проблемы написать их на C# или Java.
              Так пишутся или «не знаю, но обсуждаю»?
              Про С10к Я могу привести гораздо более развёрнутую статью с французской вики где про MigratoryData даже и не сказано. Что такие сервера есть, я уверен, есть вполне успешный сервер на питоне умеющий в С10k, но в основе они всё равно обращаются к чисто системным вызовам epoll/kqueue/iocp и так далее, но это не часть «стандартной» Java, почему я и попросил ссылку. Да и MigratoryData целиком коммерческий, может поэтому по нему очень мало информации в интернетах, в отличии от остальных (с десяток, не меньше, и бесплатных).


          1. webkumo
            14.07.2016 12:41

            Немного не в курсе — в JavaFX браузер нативненький или java-based? И ещё куча всяких embedded-браузеров. Да это не браузер общего назначения… но в браузерах общего назначения итак не протолкнуться.

            Насчёт серверов общего назначения — на Java, скорее всего, нет. Есть различные контейнеры приложений (tomcat/jetty/...), сколько они держат подключений на практике — не знаю, не интересовался. С учётом того, что основная их задача — не отдача статики, а отработка запроса в приложениии — проблемы раньше упрутся в особенности приложения.

            Ну а сервер общего назначения, выдерживающий c10k я знаю один, но он не на плюсах а на голом C написан (nginx). На плюсах есть аналог?


            1. monah_tuk
              14.07.2016 14:03

              Сервера разные, вот вам пара на C++: Nimble и EvoStream, но если посмотреть внутрянку (по импортируемым симвалом), то там беркли сокеты и poll/kqueue.


              1. sborisov
                14.07.2016 14:53

                boost.asio дёргает внутри себя
                (epoll на Linux 2.6, kqueue на FreeBSD/MacOSX, Overlapped IO на MS Windows)


                1. monah_tuk
                  15.07.2016 04:46

                  И что? Asio там не используется, Nimble — косвенное заключение да и за чаем разработчика спрашивал, а исходники EvoStreamer до того как он стал закрытым доступны: crtmpsserver, там тоже нет Asio. Правда, думаю, сейчас Evo от своего прародителя далеко ушёл.


                  А по своему опыту: нужно было написать молотилку запросов HTTP (много мелких) Asio раскачать сильно не получилось, упирался в ~250к RPS, тогда как на libev (у него встроенный C++ интерфейс есть) запросто получилось около 600к RPS. Правда это на 1k подключений, на 10к снизилось где-то в полтора-два раза, на обоих.


                  Минус решений отличных от libuv и asio: для Windows, по сути, приходится писать свой код.


                  Ну и ещё, Asio и libuv сильно обмазывают epoll снаружи, что бы его использование походило по интерфейсу на IOCP


            1. sborisov
              14.07.2016 14:50

              вот тут статья от mail.ru про c10k и boost.asio
              https://habrahabr.ru/company/mailru/blog/191756/


            1. billyevans
              15.07.2016 01:51

              Есть не совсем аналог. Но несколько лет назад он раза в 3 работал быстрее, чем nginx.
              https://github.com/mamchits/phantom
              На нем еще построена тулза для нагрузочного тестирования Яндекс.танк.


        1. sborisov
          14.07.2016 14:30
          +2

          Нет, нет, нет… заберите всё это себе… Никаких браузеров на Java и C#, кстати где вы их взяли? :)


          1. webkumo
            14.07.2016 18:09

            Хм… а чем вам не нравятся браузеры Java? Небольшие эмбеды в различные java-приложения… удобно же? Согласен, что они добавляют свои нюансы (в них не втюхивается столько сил, сколько в вебкит и файрфокс, поэтому они несколько отстают от стандарта), но их и используют только в определённых задачах (различные плюшки в тех самых java-интерфейсах; различные генераторы, например pdf).

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


        1. sborisov
          14.07.2016 14:32
          +2

          Помню когда начинались «одноклассники», был С#, потом Java и какие были тех. проблемы, когда пошёл взрывной ростаудитории и оказалось, что стоимость железа будет просто огромна, да и ЦОД таких практически не было.


      1. RomanArzumanyan
        14.07.2016 19:12
        -2

        Про потрошки Андроида — назовите меня фанатом, но таки на С. Ибо есть высокоуровневая Java, и лично я не вижу смысла прятать под капотом ещё один высокоуровневый язык программирования. Выглядит как костыль.


        1. ilmirus
          14.07.2016 19:54
          +1

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

          https://android-review.googlesource.com/#/c/247370/5/compiler/optimizing/code_generator.cc

          В андроиде на самом деле почти весь user-space на плюсах.


          1. khim
            14.07.2016 23:25
            +6

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

            На C в Android'е — только некоторое количество legacy-кода (взятого часто из разных BSD).

            Вообще весь Android — это немного «театр абсурда»: почти весь Android — написан на C++, большинство популярных программ — тоже. Но взаимодействовать им приходится через Java'у обходя кучу костылей, нужных для этого монстра. Вот что бывает когда PR ставят выше технической целесообразности… с другой стороны если бы не PR, то Android фиг бы «взлетел»: его ранние версии, по большому счёту, были весьма убоги, если бы не волшебное слово «Гугл», то не факт что его бы кто-либо сейчас ещё использовал…


          1. RomanArzumanyan
            15.07.2016 12:20

            С моей точки зрения — потрошки Андроида на плюсах — это не есть хорошо. Вот это я и хотел сказать в своём комменте. То, что они по факту написаны на плюсах — я знаю.


    1. TreyLav
      14.07.2016 08:50
      +7

      Даже долбаное кросплатформенное приложение с нативным GUI интерфейсом невозможно создать

      Единственный язык, который я вспомнил с ходу, со своей собственной реализацией кроссплатформенного GUI — это Java. И, знаете, как-то оно меня тоже не радует (как пользователя). Уж лучше Qt или другой «универсальный» тулкит.


    1. sborisov
      14.07.2016 14:28
      +1

      Раньше главные претензии были, что мало функций, маленькая стандартная библиотека, нужно больше всего, и теперь когда это пытаются дать, начали раздаваться крики «горшочек не вари». :)


      1. khim
        14.07.2016 14:59

        И оба мнения правильны, что характерно. Библиотеки нужно оформлять как отдельные подстандарты — и реализации смогут пречислять какие из них поддерживаются. Да и с языком тоже самое: Fixed point существует как отдельная сущность от всего остального — что не мешает его использовать тем, кто он нужен.


      1. TargetSan
        14.07.2016 15:00
        +4

        Это реально "горшочек". Одно только внедрение аналитической геометрии в стандарт. Хотя ей самое место в отдельном пакете. Т.е. в стандарт тащат много, но не всегда то, что реально нужно.


        1. 0xd34df00d
          14.07.2016 22:34

          Почему же? Мне вот аналитическая геометрия реально нужна, например.


          1. TargetSan
            14.07.2016 23:24
            +7

            А я не говорю, что аналитическая геометрия это плохо. Я говорю, что ей место в отдельной либе. Пусть она поддерживается комитетом, не вопрос. Но отдельно. Иначе такими темпами в стандарт захотят 3Д-движок, физический движок, библиотеку акторов и что-нибудь ещё. И тогда стандарт будет не 1600 а 16000 страниц.


            1. antoshkka
              15.07.2016 08:46

              Другими словами, вы не хотите один документ с 16000 страниц, а хотетие 10 документов по 1600.

              Мне кажется это вопрос оформления/вкуса/дизайна/скрипта-сборки-документа. О чем спор то? :)


              1. ozkriff
                15.07.2016 09:04
                +3

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


                1. dpantele
                  15.07.2016 23:17

                  Да не надо же вечно таскать, вполне себе выкидывают std::binary_function, например. Реализация какое-то время бдует содержаться, в этом проблема, да.


              1. EvgK
                19.11.2016 10:26

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


                1. 0xd34df00d
                  15.07.2016 17:14
                  +1

                  А зачем о них помнить?


      1. Videoman
        14.07.2016 17:27
        +1

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

        Был сеттер:
        void SomeClass::SetName(const std::string& first, const std::string& last);

        Теперь, в новом стандарте, есть move сематика. Теперь в лоб, получается, что для того, чтобы работали идеи авторов стандарта нужно писать что-то типа того:
        void SomeClass::SetName(const std::string& first, const std::string& last);
        void SomeClass::SetName(std::string&& first, const std::string& last);
        void SomeClass::SetName(const std::string& first, std::string&& last);
        void SomeClass::SetName(std::string&& first, std::string&& last);

        т.е., на лицо, логарифмический рост количества перегрузок функций.
        Я понимаю, что нужно теперь писать вот так:
        void SomeClass::SetName(std::string first, std::string last);

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


        1. Antervis
          14.07.2016 19:46
          +1

          > но что бы это понять и убедиться что это работает, нужно столько сил и времени
          Просто: потому что copy elision 1. и так реализован в основных компиляторах 2. является требованием с++17.

          > В итоге имеем такие затыки через каждые 20 строчек
          Вот когда замерите, увидите что у вас программа 30+% времени перегоняет пустое в порожнее, туда-обратно копирует и жрет оперативку как хром, тогда у вас будет замечательный инструментарий в виде lvalue reference/rvalue/copy elision для оптимизации копирования и использования памяти. А заниматься микрооптимизациями, да еще и без четкого понимания как это всё работает — вредить себе и проекту.


          1. Videoman
            15.07.2016 10:49

            По сути, все о чем мы тут рассуждаем и есть сплошные микрооптимизации. Это все базовые кирпичики размазанные тонким слоем и никого HotSpot-а в 30% в базывых примитивах в адекватном коде на С++ вы не увидите. С точки зрения высокоуровнего программиста, можно писать хоть на javascript. Ему С++ не нужен.


            1. Antervis
              15.07.2016 10:58

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


              1. Videoman
                15.07.2016 11:09

                Я согласен. Но, если не важны такты, то и С++03 достаточно, и все эти микрооптимизации интересны только комитету и чего мы тогда тут страдаем :)


                1. Antervis
                  15.07.2016 12:49

                  потому что из 100 случаев в одном эти микрооптимизации таки принесут пользу


                  1. Videoman
                    15.07.2016 14:00

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


                    1. Antervis
                      15.07.2016 16:37

                      Нет. Во-первых, есть много сценариев, при которых компилятор вправе сделать placement конструктор вместо перемещения. Во-вторых, многие операции перемещения в stl легальны только если соответствующие конструкторы/операторы присваивания объявлены noexcept. В-третьих, как я уже писал, перемещающие конструкторы/операторы присваивания неявно создаются только для классов, у которых не переопределены копирующий конструктор/оператор присваивания/деструктор. В четвертых, везде, где у класса не определена соответствующая мув-семантика, компилятор использует копирующие аналоги.

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


                      1. Videoman
                        15.07.2016 16:42

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


        1. GraD_Kh
          16.07.2016 11:30
          +1

          Все-таки перегрузки с const std::string&& бессмысленны. Достаточно иметь 2 перегрузки — const std::string& и std::string&&. Однако, если речь идет о сеттере, внутри которого значение захватывается по значению, то при наличии rvalue-ссылок можно передавать просто по значению:

          void SomeClass::SetName(std::string first, std::string last)
          {
              _first = std::move(first);
              _last = std::move(last);
          }
          

          Поскольку move очень дешев, то это будет практически оптимально для всех случаев:
          foo->setName(first, last);
          foo->setName(std::move(first), std::move(last));
          foo->setName("Ivan", "Pupkin");
          


          1. DistortNeo
            16.07.2016 17:10

            Так предыдущий комментатор именно это и написал. Если есть 1 параметр, то будет 2 перегрузки, если 2, то 4, если 3, то 8 (дял всех возможных комбинаций) и так далее.


            1. GraD_Kh
              17.07.2016 12:15

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


    1. myrov_vlad
      14.07.2016 15:03

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


  1. JustTry
    14.07.2016 08:16
    -2

    Сколько читаю стандарты, начиная с С++11, и нигде не вижу и намёка на встроенные библиотеки для графики. Неужели их никогда не введут?

    Обычно в языках программирования стараются снизить порог вхождения, сделать язык более привлекательным для людей. А в С++ читаешь обновления и думаешь: «А дойду ли я когда-то до этого?». Я пока новичок и решаю более простые задачи, для которых мне совсем не нужно большинство вещей из С++11/14/17. Но вот та же графика — почему ее нет? Приходится качать и подключать Qt. Аналогично с базами данных. И что забавно — в С++ всегда какие-то проблемы с подключением других библиотек. Как-будто это специально создано для мучения:)

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


    1. antoshkka
      14.07.2016 08:29

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

      Графику наврядли получится стандартизировать. Слишком большой выбор: есть Qt, WxWidgets, Gtk, EFL и многие другие.


      1. JIghtuse
        14.07.2016 08:41

        Был proposal с добавлением Cairo для 2D-графики. Он довольно низкоуровневый (GTK, Firefox его используют под капотом) и достаточно кросплатформенный. Но не знаю, как он там продвигается.


        1. antoshkka
          14.07.2016 09:10

          Cairo-подобный proposal сейчас выглядит вот так: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0267r1.pdf
          Предложение очень активно обсуждалось в Оулу, вносилось множество правок. Есть шанс через пару лет увидеть в std::experimental::


    1. Dark_Daiver
      14.07.2016 09:01
      +1

      Зачем языку, программы на котором нередко исполняются в средах где не требуется GUI встроенные средства для графики?
      В отличие от многих новых языков перед С++ проблема привлечения новых пользователей стоит не так остро, поэтому особо снижать порог вхождения не требуется.
      Для «простых смертных» есть куча других языков, которые сознательно стараются упростить процесс разработки (порой, правда, ценой производительности/гибкости/узкой специализации)


      1. encyclopedist
        14.07.2016 15:46

        В первую очередь для обучения. Детей, школьников. А то они спрашивают "а как мне нарисовать черепашку?" и получив ответ с отсылкой к каким-то непонятным библиотекам, выбирают другой язык.


        1. Tujh
          14.07.2016 15:52

          https://www.codingame.com же есть для таких целей


        1. Dark_Daiver
          14.07.2016 16:26
          +2

          С++ не очень подходит для обучения, ИМХО, даже совсем.
          Ну и в таком случае, надо отсылать к понятным библиотекам.


      1. JustTry
        14.07.2016 17:21

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

        1. Как уже ответили, для обучения. Приложения без графики новичкам писать не так интересно.
        2. Для своих приложений, которые используешь для получения опыта в использовании языка. Просто решаешь свои прикладные задачи, пишешь для этого простые программы с интерфейсом (Да, есть много других языков, где можно с легкостью создать GUI, но ведь цель — изучить С++).
        3. Да и просто для создания быстрых программ с интерфейсом. С++ ведь достаточно хорош в скорости, так почему б его не использовать для этого?


        1. Dark_Daiver
          14.07.2016 18:45
          +1

          Ну я же не предлагаю совсем отказаться от GUI в С++, я говорю, что в стандартной библиотеке (которая должна создаваться из расчета, что ее API не будет меняться десятилетиями, и что она будет реализованна для множества платформ) GUI явно излишен.

          Для графического интерфейса, в мире С++ есть решения. Тот же Qt.
          Если нужен быстрый старт, то берем Qt Creator и вперед. Подозреваю что подключить Qt в других IDE тоже не особо сложно.


    1. sborisov
      14.07.2016 15:01

      я раньше обычно для работы с БД использовал QtSQL модуль, раз уж приложение с графикой, сейчас просто подключаю libpq — и ну его нафиг — тот QtSQL. Т.к. мне доступны все возможности БД, библиотека отлично документирована, много примеров. Т.ч. не так всё страшно.
      Можно сделаьт класс обёртку, с методами — а под капотом делать бекенды которые могут с любой БД работать, хоть mongo, хоть oracle


  1. iperov
    14.07.2016 09:02
    +1

    Объясните мне,
    — что теперь каждые 3 года, когда вводят новые фишки в C++, миллионы строк кода готовых оттестированных кодобаз (библиотеки, игровые движки) должны кинуться обновлять свои сорсы под эти фишки, рискнув стабильностью своих продуктов?
    так и представляю: миллионы коммитов в древних не тронутых файлах, где меняется самое простое допустим xx::yy::zz::iterator на auto.

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

    — или предполагается совмещение стилей С++03 с новыми стандартами в одном продукте?
    т.е. листаешь ты сорсы, в одном файле xx::yy::zz::iterator, в другом — auto. Очень всё лаконично же и в одном стиле, не код, а загляденье.


    1. DistortNeo
      14.07.2016 10:13
      +1

      Принципиальных изменений в C++ не происходит. Происходит только медленное разрастание STL и добавление синтаксического сахара для увеличения простоты и уменьшения объёма кода.

      Единственное фундаментальное изменение — это move semantics.
      А так да, можно писать в стиле C++03.


      1. iperov
        14.07.2016 10:59

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

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

        Move semantics прочитал здесь. «гениально», стреляем себе в ногу дальше. Теперь каждый раз нужно лезть в класс, и смотреть, а нет ли у него move semantics внутри, чтобы знать, что этот класс нельзя использовать после копирования foo&.


        1. antoshkka
          14.07.2016 11:05
          +1

          нет ли у него move semantics внутри, чтобы знать, что этот класс нельзя использовать после копирования foo&

          Я вас не понял, распишите пожалуйста проблему подробнее.


        1. DistortNeo
          14.07.2016 11:19
          +1

          Касаемо языковых фишек: простота увеличивается за счёт использования лямбд (больше не надо писать классы-функторы), range-based for (чуть меньше кода), constexpr (вместо шаблонов и метапрограммирования). Понятность — за счёт явного указание override и final для виртуальных функций, nullptr вместо константы NULL, отказа от enum в пользу enum class.

          auto считаю злом.

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


          1. Antervis
            14.07.2016 19:54

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


            1. DistortNeo
              15.07.2016 18:09

              Да, действительно. Я просто заметил, что практически перестал использовать явные конструкторы копирования и перемещения.


          1. 0xd34df00d
            14.07.2016 22:47
            -1

            Почему auto зло?


            1. DistortNeo
              15.07.2016 00:03
              -3

              Усложняет читаемость кода.


              1. 0xd34df00d
                15.07.2016 00:12
                +1

                При должном именовании методов и переменных — ничуть.


                1. DistortNeo
                  16.07.2016 21:25

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

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


                  1. 0xd34df00d
                    18.07.2016 04:36
                    +2

                    Для публичных методов — безусловно, согласен. Более того, когда я пишу на хаскеле, которому вообще аннотации типов почти всегда не нужны, я их, тем не менее, для top-level-функций указываю.


              1. semenyakinVS
                15.07.2016 18:59

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


        1. TargetSan
          14.07.2016 11:22
          +1

          Вообще-то в rvalue reference превращаются только rvalue. А 'foo& bar' — lvalue. Здесь как раз косяков нет. Хотите переместить именованное значение — std::move. Но если после него вы используете старую переменную — ССЗБ.


          1. iperov
            14.07.2016 12:46
            -1

            Если у меня уже отлаженная парадигма классов в сервере, зачем мне добавлять новые классы с непонятным извне поведением, которое приведет к ССЗБ?
            Весь этот огород с move semantics, когда однозначно не понятно, в каких случаях класс копируется, а в каких перемещаются кишки, и тогда старая переменная не валидна для использования, потому что внутренний хендл переместили. И что тогда в каждую функцию File добавлять проверку на валидность хендла? Адская избыточность. Зачем эти усложнения?

            В той хабра статье уповают только на использование динамической памяти там, где она мол не нужна.
            Какие сейчас проблемы с памятью? У меня на сервере свой MM, предвыделенные чанки (расширяются автоматически) от 8 байт до 32кбайт с шагом по экспоненте, в неблокирующем ring buffer'e.
            Выделить 8-32кбайт на хендл затрат проц времени для ММ около нуля, зато получаем более управляемый код. Это я имею ввиду использовать хендл в обвязке умного указателя.

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


            1. mayorovp
              14.07.2016 13:00
              +2

              Да почему непонятно-то? Как раз наоборот, все предельно просто.


              "Кишки перемещаются" ровно в двух случаях:


              1. когда старое значение более не доступно;
              2. когда программист явно написал std::move

              Если вы не будете использовать std::move — вы никогда не натолкнетесь на невалидные переменные.


              Сейчас тенденция везде использовать умные указатели для управляемости и читабельности, и я не понимаю смысла ввода move semantics в виду этой тенденции

              Все просто: move semantics придумали чтобы сделать нормальные умные указатели. К примеру, uniqie_ptr без семантики перемещения нельзя было бы использовать в STL-контейнерах.


              1. TargetSan
                14.07.2016 13:22
                +3

                Все просто: move semantics придумали чтобы сделать нормальные умные указатели. К примеру, uniqie_ptr без семантики перемещения нельзя было бы использовать в STL-контейнерах.

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


                1. Videoman
                  14.07.2016 17:55
                  -3

                  Ничего не просто. При move, копирование все-равно происходит. Это не панацея, а всего лишь еще один уровень оптимизации. Если у вас класс имеет 100 полей move придется их все копировать. Т.е. RVO и Copy-Elision предпочтительней, а const& все еще нужен. Этот экспоненциальный рост количества перегрузок, при проектировании интерфейсов, не добавляет простоты.


                  1. Antervis
                    14.07.2016 20:04
                    -1

                    если при муве происходит копирование, значит вы что-то делаете не так


                    1. Videoman
                      15.07.2016 10:54

                      Да конечно… :). Например в std::string, обычно, есть оптимизация, где маленькие строки, до 16 байт, хранятся в статическом массиве в самом std::string. Как, по вашему, должен быть реализован конструктор перемещения в таком случае?


                      1. Tujh
                        15.07.2016 11:58
                        -1

                        Вот только это «обычно» относится к одной-двум версиям библиотек и с появлением С++11 я не уверен, что этот «финт ушами» сохранился. В С++03 были и реализации, которые строку хранили по частям, разбивая на блоки фиксированного размера, в С++11 появилось требование о непрерывности блока памяти, хранящего данные строки.


                        1. Videoman
                          15.07.2016 12:06
                          +1

                          Я смотрел. Он сохранился. Более того, это теперь почти единственная оптимизация для строк которая есть на практике, т.к. требования к строке в С++11 таковы, что теперь даже COW невозможен и все реализации библиотек переделываются чтобы учитывать новые требования.


                          1. Tujh
                            15.07.2016 14:21

                            ОК, буду знать, спасибо!


                        1. antoshkka
                          15.07.2016 12:16

                          В C++11 этот финт ушами только и разрешили делать. Начиная с C++11 все реализации строки с COW или хранящие строку по частям, или не держащие на конце '\0' — не являются валидными имплементациями.

                          И слава богам! Замена COW строки на строку со small-buffer optimization в двух абсолютно различных проектах давала прирост производительности более 10% (мой личный опыт). Знакомые из других проектов подтверждают прирост в производительности.

                          Для не верящих есть целая статья http://www.gotw.ca/publications/optimizations.htm


                          1. Tujh
                            15.07.2016 14:20

                            Получается, что в случае «длинных» строк, мы получаем overhead по памяти, за счёт не используемого буфера в те самые 16 байт? Или его начинают использовать в других целях (указатель на память в куче и т.п.)?


                            1. Videoman
                              15.07.2016 14:46

                              Именно так.


                            1. antoshkka
                              15.07.2016 15:26
                              +2

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


                  1. TargetSan
                    15.07.2016 10:33

                    Если вы таскаете по стеку структуру на 100500 полей, вы делаете что-то не так. А мув служит для почти бесплатного перемещения контейнеров, у которых маленьая часть на стеке и большая в куче. Простой пример — вектор на пару сотен килобайт. Без мува, при отдаче владения в функцию, у вас будет копирование. Толстое. С выделением ещё одного куска на пару сотен килобайт и копированием всего содержимого. С мувом — старый вектор отдаст новому владение буфером. И будет "копирование" 1 указателя. С занулением его на старом месте.


                    1. Videoman
                      15.07.2016 11:02
                      -1

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

                      Бесплатного для того кто использует, а для того кто пишет эти классы :)?


                      1. TargetSan
                        15.07.2016 11:14
                        +3

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


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


                        1. Videoman
                          15.07.2016 11:26

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


                          1. Tujh
                            15.07.2016 11:59
                            +1

                            Майерс доступен уже даже на русском с полгода минимум. Как обычно — всё пережёвано и готово к употреблению.


                      1. encyclopedist
                        15.07.2016 17:07
                        +1

                        Почти бесплатно.


                        Современная концепция состоит в том, что управление ресурсами должно осуществляться в специальных листовых классах. Это могут быть умные указатели или самописные классы. В этих классах да, придётся самому написать все 5 спец-методов (см "Rule of Five"). Но таких классов должно быть немного (по одному на каждый вид ресурса, причём для самых распространённых ресурсов "память" и "открытый файл" такие менежджеры уже реслизованы в стандартной библиотеке).


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


                        Эта концепция известна под именем "Rule of Zero".


                        1. Videoman
                          15.07.2016 17:12

                          Ох уж эти теоретики… хорошо, запомним. Будем стараться осваивать все эти современные концепции. Главное, чтобы они не менялись быстрее, чем программисты их успевали изучать.


        1. Dudraug
          14.07.2016 14:40
          +3

          Теперь каждый раз нужно лезть в класс, и смотреть, а нет ли у него move semantics внутри, чтобы знать, что этот класс нельзя использовать после копирования foo&.


          Мне кажется вы не поняли move сементику. Проблемы никакой нет. Прочитайте еще раз до полного просветления.


    1. johny
      14.07.2016 10:29

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

      Не нужно кидаться и обеспечивать поддержку всего-всего на свете.

      Как-то в сфере веба довольно часто всё обновляется, но живет же как-то эта сфера.


  1. Lauren
    14.07.2016 09:02
    +8

    Пора рефакторить язык


  1. Tujh
    14.07.2016 09:02
    +2

    std::string::data(), возвращающий неконстантый char* (УРА!);
    Может я не сталкивался просто, а что не так было с константностью этого метода? Вполне логично, что получая «сырые» потроха строки их нельзя менять, как мне кажется.


    1. Antervis
      14.07.2016 11:21

      проблема в том, что некоторые неблагородные API (и майкрософт грешит этим чаще остальных) часто просят, например, wchar_t* вместо const wchar_t* даже когда не меняют строку.


      1. Gummilion
        14.07.2016 15:51

        Для таких неблагородных есть const_cast, зачем еще новый метод добавлять?


        1. 0xd34df00d
          14.07.2016 22:49

          const_cast пахнет. Очень.


          1. khim
            14.07.2016 23:35

            И хорошо что пахнет: сразу видно где у вас кривизна в API. А так — вы её просто будете вытаскивать дальше по стеку. И у вас тоже появятся функции, принимающие std::string& вместо const std::string&, но при этом строку не меняющие. Кому от этого лучше станет?

            Мне вот интересно в какой версии C++ конструктор string'а станет наконец-то constexpr… В 20й? Или в 50й?

            Как писал Джоел: Интересно, что историю развития C++ можно описать как историю затыкания дырок в абстракции строк. Уж не знаю, отчего бы не добавить к языку элементарный класс строчек.

            Пока что наблюдение продолжает иметь силу :-)


            1. 0xd34df00d
              15.07.2016 00:15

              Лучше станет мне: глаза вытекать не будут. API какого-нибудь там Windows я всё равно поменять не в состоянии, так чего мне нервничать лишний раз?

              А функции не обязаны принимать std::string& вместо const std::string&, достаточно передавать std::string, по значению на самом нижнем, оборачивающем уровне.


              1. DistortNeo
                15.07.2016 18:05

                Если передавать std::string, то будет лишнее копирование при невозможности перемещения при передаче параметра в функцию.


                1. 0xd34df00d
                  16.07.2016 20:21

                  Да, но это, возможно, и не важно, особенно если вы дёргаете функцию для I/O или, того хуже, сети.


                  1. DistortNeo
                    16.07.2016 21:21

                    Да, в случае работы с сетью частая ошибка: уничтожить буфер до того, как он будет фактически отправлен. Тут действительно лучше скопировать — надёжнее будет.


                    1. 0xd34df00d
                      20.07.2016 01:16

                      Конкретно тут не соглашусь, разницы нет никакой (если не учитывать многопоточность) :)

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


            1. Antervis
              15.07.2016 06:02
              +1

              > Мне вот интересно в какой версии C++ конструктор string'а станет наконец-то constexpr…
              Если вы знаете, как сделать constexpr-конструктор для класса, владеющего памятью на куче, срочно оформляйте proposal! Это же столько дряни в компайл-тайм перетечет!


              1. bull1251
                19.11.2016 03:03
                -1

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

                В качестве примера рассмотрим эксперимент с отложенным выбором, который был предложен Скалли и Дрюлем:
                В дальнейшем установка усложняется. Причем дальнейшее действия будут во многом отличаться от предложенного эксперимента Скалли и Дрюля. Я не стал описывать всех деталей предполагаемого мной эксперимента, оставив для читателя возможность самостоятельно решить эту задачу. А чтобы получить интерференционную картину, в последующем необходимо будет стереть информацию о том, через какой путь прошли фотоны. Например, направив холостые фотоны обеих направлений в один даун-конвертор, дающий на выходе «50 на 50» вероятности того, через какой путь прошли фотоны.

                Я читал ваши комментарии, и в особенности хотелось бы отметить данный текст:
                Если фотон попал в D1 или D2 — информация о пути «стерта». Если мы удалим маркеры со всех фотонов, они все попадут в D1 или D2. Но важный момент в том, что мы получим ДВЕ интерференционные картины (для фотонов из D1 и D2 соответственно), причем пики одной совпадают с впадинами другой. Соответственно эти две картины в сумме дают обычное хаотическое распределение (которое мы и видим на экране).
                Дело в том, что ДВЕ интерференционные картины при наложении дают хаотическую картину, только когда используются два лазерных луча разного спектра (красного и синего). Предположение верное, но только в рамках указанного вами эксперимента. А когда используется один лазер, такого смещения не происходит.


                1. antoshkka
                  15.07.2016 08:54

                  Это будет std::string_view а не std::string.

                  std::string_view имеет в C++17 constexpr конструкторы и операторы, но часть операций зависит от CharTraits, где аналогичные операторы тоже должны быть помечены как constexpr.


                1. rzhikharevich
                  15.07.2016 08:55
                  +1

                  То, что его нельзя будет затем ресайзить?


                1. Antervis
                  15.07.2016 09:27

                  если говорить конкретно про std::string, то тогда надо будет добавлять флаг того, что строка ссылается на константную строку в памяти. Соответственно, при попытке модифицировать строку будет происходить отложенное выделение памяти, копирование, модификация и пр. Т.е. сделать constexpr string(const char *) таким образом в принципе можно, вот только string+string или другие тривиальные операции уже constexpr не сделаешь. Помимо этого все операции будут проверять флаг и сама строка вырастет в размерах. Получается размен шила на мыло.

                  Вариант 2: сделать конвертируемую в std::string constexpr-оболочку поверх const char*. Тогда оболочка-то будет constexpr, а сам string будет создаваться из неё в рантайме. Т.е. тоже бесполезно.


              1. crackedmind
                15.07.2016 11:02
                +1

                Был пропозал отдельный на fixed_string http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0259r0.pdf На сайте автора пропозала можно найти реализацию.


  1. TargetSan
    14.07.2016 09:13

    Кстати, из чистого интереса. std::vector, std::string научились конструироваться из сырого буфера и отдавать свой сырой буфер?


    1. Tujh
      14.07.2016 09:18

      отдавать — вроде давно научились std::vector::data/std::string::data, начиная с С++11 метод data должен возвращать указатель на корректную нуль-терминированную строку.

      The pointer returned points to the internal array currently used by the string object to store the characters that conform its value.
      Both string::data and string::c_str are synonyms and return the same value.

      http://www.cplusplus.com/reference/string/string/data/


      1. TargetSan
        14.07.2016 09:21
        +1

        Нет, я не про то. Я про возможность отобрать владение таким буфером и отдать кому-то ещё.


        1. Tujh
          14.07.2016 09:29
          +1

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


    1. pravic
      14.07.2016 10:05

      string_ref не владеет буфером, поэтому можно её использовать в таких случаях.
      Или нужно что-то наподобие unique_ptr, который принимает готовый указатель и владеет им, пока явно не отдашь (release)? Но зачем?


      1. monah_tuk
        14.07.2016 14:07

        Отдать владение в какое-то API. Бывает необходимо. Сейчас аллоцируешь сам, копируешь и уже новое отдаёшь.


    1. Antervis
      15.07.2016 09:38
      +1

      для таких целей скорее нужен std::unique_ptr<T[]>


      1. TargetSan
        15.07.2016 10:36

        С ним банально неудобно работать. Один из кейсов, пусть и редких — набить с помощью вектора массив данных и скормить вместе с владением какой-нибудь функции.


  1. AxisPod
    14.07.2016 10:22

    Капец, когда забривали всякие вещи, потому что они дублируют функционал и при этом замена была действительно лаконичной, объемы кода заметно уменьшались, а тут нате вам корявый if с инициализацией. Если уж хотелось что-то подобное, лучше бы сделали аналог using из C#, было бы куда полезнее, чем этот костыль.


    1. mayorovp
      14.07.2016 13:07
      +2

      Ну, реализовать using-то теперь можно без проблем:


      #define using(x) if(x; 1)


      1. AxisPod
        14.07.2016 13:09

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


        1. mayorovp
          14.07.2016 13:22
          +1

          Для while такое уже есть, называется for :)


          1. AxisPod
            14.07.2016 13:24

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


            1. xaizek
              14.07.2016 13:57

              А вот это действительно странно, объявление переменных в условии это общее свойство if/switch/while/for, а расширили синтаксис только для if и switch. Причём добавлять в for может не захотели из-за изменения его структуры, а вот чего while пропустили непонятно.


              1. Dionis_mgn
                14.07.2016 14:24

                Для for оно работает уже уйму лет.


                1. khim
                  14.07.2016 15:04

                  Только для описания переменных одного типа, впрочем…


                1. xaizek
                  14.07.2016 15:36

                  Я не о i:


                  for (int i = 0; i < 10; ++i) ...

                  А о e:


                  for (int i = 0; error_code e = check_i(i); ++i) ...

                  Могли бы расширить (для единообразия, практической пользы тут не так уж и много) до:


                  for (int i = 0; error_code e = check_i(i); has_error(e); ++i) ...

                  (здесь e вычисляется и проверяется на каждой итерации)


  1. laughman
    14.07.2016 10:43

    «void get_vendor_from_id(std::string_view id) „

    и тут же:
    “Осторожно: string_view не гарантирует, что строчка, которая в нем хранится, оканчивается на символ '\0', так что не стоит использовать функции наподобие string_view::data() в местах, где необходимо передавать нуль-терминированные строчки.»

    почему бы сразу не рассмотреть std::string get_vendor_from_id(std::string_view id)?


    1. antoshkka
      14.07.2016 10:48
      +1

      Оператор вывода в поток перегружен для std::string_view. Это значит что строчки не оканчивающиеся на '\0' всё равно будут корректно выедены.


      1. laughman
        14.07.2016 11:32

        вопрос про вывод в std::string


        1. antoshkka
          14.07.2016 11:43

          std::string умеет конструироваться от std::string_view. std::string копирет строчку из std::string_view и добавляет '\0' в конец строки.

          std::string_view id{"Vasya Pupkin:Super Stuff"};
          std::string_view vasya_sb = id.substr(0, id.find_last_of(':'));
          std::string vasya{ vasya_sb };
          
          assert(vasya == "Vasya Pupkin");
          


          1. laughman
            14.07.2016 11:44

            спасибо


  1. SergeySib
    14.07.2016 11:26

    Почему же при такой любви Комитета к функциональщине, в стандартную библиотеку еще не внесли «джентльменский набор» из всевозможных apply, fold, map, zip, zipWith и т.д., создающих последовательности вызовов на этапе компиляции? Ведь все предпосылки уже есть, и часто приходится самостоятельно писать вещи для std::array или std::tuple с различной степенью кривизны. Планируется ли что-нибудь из этого в ближайшем будущем кроме уже внесённого apply для кортежей?


    1. antoshkka
      14.07.2016 11:35

      apply и make_from_tuple приняли в C++17
      fold — в C++17 есть fold expression наподобие variable_pack +…
      zip, map — нет изкоробочного, готов помочь с написанием proposal если вам интересно


  1. MCoder
    14.07.2016 11:26
    +1

    Согласен с высказываниями выше насчет строк и т.п. Действительно перегрузили язык уже и так. Пишу на с++ постоянно. Но сил уже нет изучать новые хитрости и премудрости. Qt очень и очень радует. Есть еще Poco Library для некоторых вещей. В принципе вот куда надо смотреть. Язык надо упрощать, чтобы было приятно на нем писать.


  1. volkoff_roman
    14.07.2016 11:26
    +1

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

    Злой тролль-сишник так и не осиливший плюсы.


    1. Idot
      14.07.2016 11:52

      Borland C++ Builder?


      1. volkoff_roman
        14.07.2016 12:01
        +1

        Qt


    1. encyclopedist
      14.07.2016 15:54

      Пропозал по графике на основе Cairo уже в процессе.


  1. crackedmind
    14.07.2016 11:43
    +6

    Радует что при использовании structured bindings можно будет проще по мапу итерироваться, а не ковырятся с first/second

    for(auto [key,value]: my_map) {
    }


  1. Shamov
    14.07.2016 11:44
    +1

    Не верится, что уже в следующем году всё это будет законно. Особенно мне нравится первый пункт — constexpr if. Я пока не знаю точно, где и как я это буду использовать, но уверен, что эта фича станет моим новым фаворитом.


  1. RomanArzumanyan
    14.07.2016 12:18
    +8

    Есть мнение — на собеседованиях вопросов прибавится. Код останется прежним.


  1. ivann
    14.07.2016 14:03

    Для каких переменных используется именование с подчеркиванием на конце? Например, valuesmutex.


    1. crackedmind
      14.07.2016 14:37

      Обычно такой convention используют для private элементов.


  1. Gummilion
    14.07.2016 16:23

    А с новыми плюшкками получится сделать обмен переменных, написав [a, b] =[b, a] (или еще auto добавлять надо)?


    1. Shamov
      14.07.2016 17:08
      +1

      А смысл? Чтобы использовать в процессе обмена две временных переменных вместо одной?


    1. crackedmind
      14.07.2016 17:39
      +4

      std::swap то чем не угодил?


  1. Randl
    14.07.2016 21:03
    +1

    Интересно что люди одновременно хоронят С++ за лишние фичи и за из отсутствие. Причем одни и те же фичи одновременно ругают и хвалят куча людей.


    Кто не верит в комитет — вступайте и действуйте ИМХО. Кто не верит в С++ — развивайте/пользуйтесь альтернативами


    1. totally_nameless
      15.07.2016 12:20
      +6

      «Есть всего два типа языков программирования: те, на которые люди всё время ругаются, и те, которые никто не использует.»
      — Bjarne Stroustrup.


  1. Satus
    15.07.2016 12:20
    -1

    Когда я читаю про новые стандарты С++, сначала я думаю «Вау, круто, этого мне и правда не хватало!», потом «Когда всё это учить?», а под конец «Как все эти данные держать в голове вообще?»


    1. Tujh
      15.07.2016 14:22
      +2

      Ищите положительные стороны, изучив всё эти фишки и умея их применить на практике эффективно можно стать очень ценным и высокооплачиваемым специалистом :)


  1. semenyakinVS
    15.07.2016 17:05
    -1

    А может кто-нибудь, кто лучше в разбирался в теме, рассказать о проблемах с концептами в плюсах? Просто я ещё понимаю, когда речь идёт о полноценном языке контроля AST — это понятно почему трудно. Но мне всегда казалось, что в концептах как в фиче нет ничего сложного хотя бы потому, что она никак не влияет на кодогенерацию (если не рассматривать возможные оптимизации, которые компиляторы смогут делать благодаря концептам). Фактически, это что-то вроде встроенного в язык редактора правил для статического анализатора… Или я ошибаюсь?


    1. encyclopedist
      15.07.2016 17:17
      +1

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


      1. semenyakinVS
        15.07.2016 17:37
        -1

        Ух ты, погуглил — точно! Где-то очень вскользь встречал что будут такое делать — но как-то мимо прошло, надо же. Спасибо, смотрю вот теперь чего там в gcc наделали. Первый же пример впечатляет — ограничение на перечень методов объекта-аргумента. Я так понимаю, так же и с шаблонным аргументами можно?

        Быстрее бы до ума довели.


  1. kdekaluga
    19.07.2016 15:01
    +1

    Вот смотрю на «рост» С++ и всегда удивляюсь — почему такую простую вещь, как for… else никак не реализуют? Неужели это никому не надо?
    Представим ситуацию поиска элемента где-либо (например, в массиве):

    item a = ...;
    for (...)
    {
      item b = ...;
      if (a == b)
      {
        // We've found the item
        do_something ();
        break;
      }
    }
    // We are here in both cases when we've found <a> and when we haven't.
    


    Без введения дополнительных проверок или использования goto различить причины «выхода» из цикла невозможно.


    1. khim
      19.07.2016 15:53

      Как показала моя практика: программисты на Питоне (где эта конструкция есть, если не ошибаюсь, с самого начала) смотрят на тебя «квадратными глазами» (и просят «исправить отступы», что, понятно, всю логику изменит), когда ты эту конструкцию используешь. Не все, но многие.

      Проблема курицы и яйца: for...else люди не используют потому что не знают, а раз не знают — то и в стандарт добавить её некому…


    1. lemelisk
      19.07.2016 16:08

      С новым синтаксисом, насколько я понимаю, можно будет написать как-нибудь так:

      if (auto result_it = std::find(std::begin(container), std::end(container), a)
          ; result_it != std::end(container)) {
        do_something();
      } else {
        ...
      }
      


      1. kdekaluga
        19.07.2016 16:51

        Да, если речь идет о простом поиске в контейнере — в stl есть варианты (даже сейчас). Но меня интересует именно конструкция языка. Например, я делаю итеративные расчеты с ограниченным количеством итераций (лимит в for), и если на какой-либо итерации я достигаю заданной точности, выхожу из цикла досрочно (break), если же за определенное количество итераций достигнуть требуемой точности не получается, я должен предпринять какое-либо еще действие. Понятно, что в таком примере один лишний if на ситуацию вряд ли повлияет, но по мне это именно тот случай, где задача едина для всех платформ и компиляторов и четко формализована.


        1. lemelisk
          19.07.2016 17:49

          Можно завернуть код в «фиктивную» лямбду c мгновенным вызовом и выходить не break'ом, а return'ом:

          [&]{
            for (...) {
              ...
              if (...)
                return;
            }
            // Else part
            ...
          }();
          


        1. JIghtuse
          19.07.2016 18:51

          Если можно завернуть поиск в функцию, можно (будет) использовать std::optional, у которого как раз семантика «значения может не быть».


          1. kdekaluga
            20.07.2016 18:31

            Можно, конечно. Варианты есть всегда)
            Но для чего вводят if (init; cond)? Ведь и без этой конструкции варианты есть. Вот так же и тут)


        1. Antervis
          19.07.2016 20:43
          -1

          > Например, я делаю итеративные расчеты с ограниченным количеством итераций (лимит в for)
          ну и итерируйтесь не до end(), а до advance(begin(),N). Для random access итераторов (например, в векторе) можно даже писать begin()+N.

          Если там какая-то совсем сложная логика, то проще либо на функции разбить (и возвращаться через return), либо (на крайний случай) булевый флаг завести. И то вызовет меньше вопросов

          А если уж и заводить такой функционал, то назвать как минимум не else, а interrupted/finished, например


          1. kdekaluga
            20.07.2016 18:32

            Какое именно слово использовать для такой конструкции — не столь важно. Вопрос в том, почему бы ее не ввести вообще, если уж дошли до if (init; cond)


            1. Antervis
              21.07.2016 06:05

              разница в том, что if (init; cond) очень удобен, например, для раннего возврата, проверки защищенных мьютексами переменных (навскидку). И им гарантированно будут пользоваться. Что до for… else — я о существовании такой конструкции узнал только сейчас, хотя уже кодил на питоне


    1. lemelisk
      20.07.2016 22:10
      +2

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

      if (...)
        for (...)
          one_code_line_action;
      else
        ...
      


      1. kdekaluga
        21.07.2016 02:52
        +1

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

        1. Ввести новое ключевое слово. Не самый лучший вариант, однако, например, в С++11 появилось же auto. Вполне возможно, что раньше оно использовалось где-то в программах.

        2. Использовать комбинацию ключевых слов, например:

        for (...)
          {...}
        for else
          {...}
        


        3. Использовать >> или ->. На мой взгляд, внешне будет неплохии решением:
        for (int i = 0; i < 5; ++i)
          if (get_byte_from_stream () == value)
            break;
        >>
          send_byte_to_stream (value);
        
        ...
        
        for (int i = 0; i < 5; ++i)
          if (get_byte_from_stream () == value)
            break;
        ->
          send_byte_to_stream (value);
        


        4. Использовать ключевое слово continue. По текущему синтаксису оно используется так:
        continue;
        


        Здесь же будет

        continue statement
        
        for (int i = 0; i < 5; ++i)
          if (get_byte_from_stream () == value)
            break;
        continue
          send_byte_to_stream (value);
        
        


        1. khim
          21.07.2016 03:27

          Не самый лучший вариант, однако, например, в С++11 появилось же auto.
          auto было ключевым словом с 70х годов, однако.

          Вы бы лучше бы какой-нибудь decltype вспомнили…

          А насчёт комбинации ключевых слов можно своровать подход у Ады и использовать or else (или даже просто or).

          P.S. Вы не поверите, но и and и or и даже not — в C++ являются ключевыми словами!


          1. kdekaluga
            21.07.2016 03:36

            auto было ключевым словом с 70х годов, однако.

            эх, забыл, каюсь) думал про decltype, но auto же короче)

            Ну, на самом деле, сейчас (лично) мне нравится больше вариант continue либо >> (->). Но, по большому счету, это все равно ничего не изменит)


          1. kdekaluga
            21.07.2016 03:40

            Да, на счет or, and и not — все верно, в стандарте они есть. Но вот только, например, MSVC2012 ничего про них не знает, позволяя написать такое:

            int or = 5;
            int and = or + 1;
            and++;
            


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


  1. Sliver
    20.07.2016 04:34
    +2

    1. Выход из вложенных циклов без goto планируется?
    2. Планируется ли 'continue' блок для for/while, опять же, чтобы избежать goto и отличить нормальный выход из цикла от break?


    1. kdekaluga
      21.07.2016 03:04

      Согласен, тот же break сейчас используется без параметров, можно было бы ввести

      break n;
      

      где n — число вложенных циклов, из которых надо выйти (и, например, 0 — для выхода из всех циклов, сколько бы их не было).


      1. Antervis
        21.07.2016 07:39
        +1

        так это сложнее читать чем goto


        1. kdekaluga
          21.07.2016 13:42
          +1

          Я лично (так как начинал программировать с ассемблера) никогда против goto не был)
          Когда стал изучать С++ (С), мне достаточно успешно внушили, что лучше заводить флаг и пару ифов, но только не goto (что типа компилятор разберется и оптимизирует, а читать будет легче). Потом посмотрел исходники больших проектов и увидел goto там. С тех пор использую сам при необходимости без особых зазрений совести. Но встречал людей, для которых goto — как начало третьей мировой войны.


          1. khim
            21.07.2016 15:55
            -1

            Но встречал людей, для которых goto — как начало третьей мировой войны.
            Угу. При этом те же самые люди без зазрения совести используют, switch, break, continue — и канючат на тему «расширения их функциональности».

            Карго культ какой-то. Как будто проблема goto — не в усложнении логики программы, а в том, что это слово портит карму.

            Да, goto следует избегать, так как они запутывают логику — но компилятору они ничуть не мешают (он всё равно все ваши циклы превращает в базовые блоки и goto), а запутать логику работы флажки могут похлеще любого goto. Собственно любая программа с любым количеством goto может быть превращена в программу без goto добавлением одной переменной (next_basic_block, ага), что и показывает ущербность подхода с флажками.

            Ещё раз, для тех кто в танке: «программа с одним, всего лишь одним флажком (правда многопозиционным) может быть также сложна в отладке, как любая программа с любым количеством goto». Прэлестно, правда?


            1. Idot
              22.07.2016 11:53

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


      1. DarkEld3r
        21.07.2016 11:15
        +2

        Это ещё рефакторить менее удобно. Добавился цикл — надо будет посмотреть не используются ли внутри break/continue n. Лучше уж с именованными метками.


  1. easimonenko
    20.07.2016 19:18

    По-поводу конструкции if (init; condition) .... Почему не сделали как в некоторых других языках, например, вот так: let { init; } if (condition) ... или if (condition) ... where { init; }?


    1. ozkriff
      20.07.2016 19:25
      +2

      let… where

      что бы ключевые слова новые не вводить?


    1. Sliver
      21.07.2016 07:35
      +3

      Неясно, чем


      let { init; } if (condition) { ... }

      хоть немного лучше, чем сегодняшнее


      { init; if (condition) { ... } }

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


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


    1. Azoh
      21.07.2016 12:20

      Тогда было бы логичнее сделать отдельное выражение let (init) something, которое было бы семантически было бы эквивалентно { init; something }

      Тогда можно было бы использовать его не только для if и while, а в любом подобном месте. Скажем, в примере с захватом мьютекса мне может и не надо ничего проверять, я просто хочу захватить мьютекс, выполнить какое-то действие, а потом мьютекс отпустить.
      let (std::lock_guard<std::mutex> lock(m)) if (!container.empty()) { // do something }

      let (std::lock_guard<std::mutex> lock(m)) { // do something }


      1. lemelisk
        21.07.2016 14:53
        +2

        Вторая строчка эквивалентна простому:

        {
          std::lock_guard<std::mutex> lock(m);
          // do something
        }
        

        Цель же введения этого нового способа записи в стандарт в банальной экономии строк кода.


      1. FlexFerrum
        21.07.2016 18:13

        Тут же в другом фишка. Иногда (и не так редко, как кажется) требуется, чтобы область действия lock'а совпадала с областью действия оператора if. Находилась в рамках его скоупа. Любой «двухстрочный» эквивалент не соответствует этой хотелке. Вот другой пример на это же:

        if (ResultCode rc = DoSomething(); rc.Failed())
        {
        // обрабатываем ошибку, отваливаем
        }
        


        В рамках текущего стандарта это выглядит так:
        ResultCode rc;
        if ((rc = DoSomething()).Failed())
        {
        // Обрабатываем ошибку
        }
        

        Довольно, как это говорят, ugly. Предвосхищая вопрос. Такие конструкции могут использоваться в библиотечных «обёртках» над стандартной обработкой ошибок, логированием и т. п. То есть типа:
        CHECK_SUCCEEDED_RETURN(DoSomething()) << «Приключилась адская хрень»;


  1. sborisov
    22.07.2016 11:38

    «Автоматическое определение шаблонных параметров для классов»

    интересно, как выкрутились, т.к. Страуструп декларировал:
    Язык программирования С++ 386 стр.
    «Обратите внимание, что параметры шаблона класса (в отличие от шаблона функ-
    функции) никогда не выводятся. Причина заключается в том, что гибкость, обеспечивае-
    обеспечиваемая наличием нескольких конструкторов класса, во многих случаях является непреодолимым
    препятствием на пути такого выведения, и еще в большем числе случаев
    выведение неоднозначно. Специализация предоставляет механизм неявного выбора
    из различных реализаций класса (§ 13.5).»


    1. sborisov
      22.07.2016 11:41

      Или из 4го издания стр. 686

      Note that class template parameters are never deduced. The reason is that the flexibility pro-
      vided by several constructors for a class would make such deduction impossible in many cases and
      obscure in many more. Instead, specialization (§25.3) provides a mechanism for implicitly choos-
      ing between alternative definitions of a template. If we need to create an object of a deduced type,
      we can often do that by calling a function to do the deduction (and creation). For example, con-
      sider a simple variant of the standard library’s make_pair() (§34.2.4.1):
      template<typename T1, typename T2>
      pair<T1,T2> make_pair(T1 a, T2 b)
      {
      return {a,b};
      }
      auto x = make_pair(1,2);
      auto y = make_pair(string(«New York»),7.7);
      // x is a pair<int,int>
      // y is a pair<str ing,double>


    1. DistortNeo
      22.07.2016 15:43
      +1

      Выкрутились вот так:
      http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0091r2.html#uec
      Грубо говоря, принцип аналогичен вызову функций, только для конструкторов.

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