Идти к стоматологу, куда ж ещё. Врачи тоже бывают криворукими, и даже самый хороший специалист может совершить ошибку, но, сами понимаете, никто лучше их не умеет чинить ломающуюся тушку.
Вам, видимо, очень не повезло, да ещё и несколько раз подряд, я за всю жизнь побывал у стоматологов раз пятдесят, выдрал шесть зубов (мудрости, которых у меня шесть, а не четыре, как у нормальных людей плюс один обычный), ни раз не было даже сильно больно, не говоря уж о травмах.
Недостаток авторского решения в отсутствии синтаксической подсветки лямбд (стринга и стринга), но в случае изменения интерпретатора придётся и вовсе патчить плагин IDE, чтобы он тоже понимал такие выкрутасы… Хотя по производительности и правда гораздо дешевле
Извините, конечно, но разобраться по контексту, что делает та или иная конструкция, и написать её без знания языка — вещи совершенно разные.
Если угадать, что делает |x|*n по контексту(как и большинство других конструкций в других языках программирования) может большинство более-менее опытных разработчиков, то для того, чтобы додуматься так написать без примера, нужно обладать ну очень богатой фантазией.
Худшие, по моему очень субъективному и зачастую основанном на слухах в сообществе, мнению, компании, лично я обхожу за версту, и уж точно не думаю о том, чтобы поработать в них.
И вот тут непонятно, ожидается ли, что должен я указать недостоверные подозрения о компании, которую считаю плохой, или отвечать более-менее объективно, но о работодателе, к которому особых претензий не имею?
И ещё — возможно, это какая-то бага в опросе, но о «любимой» компании почему-то не спрашивали ничего, а о «плохой» — дважды просили указать особенности… Вот прям не знаю, что теперь делать…
Хотел только добавить, что Вы зря прибедняете C# насчёт корутин :)
Там они именно что есть, да ещё и в двух разных вариантах, обуславливаемых разными синтаксическими конструкциями - yield return / yield break и await.
Более того, именно из C# корутины приехали в C++, это было предложение Майкрософтов, вдохновлённое наработками из развиваемого ими языка.
Только корутины в C++, будучи развитием уже отработанного подхода, чуть более универсальны: у нас тоже есть три ключевых слова co_yield, co_return и co_await, (на "кококо" все ругаются, но Комитет побоялся использовать для ключевых слов распространённые английские слова, чтобы не ломать обратную совместимость) но по сути это всё - частные случаи оператора co_await.
Так ведь ради краткости и эффективности кода ведь всё и задумывается, причём в эту сторону движутся и C#, и C++, и все остальные языки программирования!
Просто для обеспечения этой простоты и эффективности разработчикам библиотек нужно порой проделать очень немало работы, это относится и к C#, и C++.
Давайте, например, посмотрим на одну из сложнейших языковых фич, корутины: смотрите, вот, к примеру, 250 строк жуткого кода , описание шаблонного типа generator. Без поллитры не разобраться, не правда ли?
Однако это - библиотечный тип, его реализовали один раз опытные люди, и теперь простым смертным достаточно его только использовать:
#include <cppcoro/generator.hpp>
using namespace cppcoro;
using namespace std;
generator<uint64_t> fibonacci()
{
uint64_t a = 0, b = 1;
while (true)
{
co_yield b;
auto tmp = a;
a = b;
b += tmp;
}
}
void usage()
{
for (auto i : fibonacci())
{
if (i > 1'000'000) break;
cout << i << endl;
}
}
В C# это выглядело бы примерно так:
using System;
using System.Collections.Generic;
IEnumerable<UInt64> Fibonacci()
{
UInt64 a = 0, b = 1;
while (true)
{
yield return b;
var tmp = a;
a = b;
b += tmp;
}
}
void Usage()
{
foreach (var i in Fibonacci())
{
if ( i > 1000000 ) break;
Console.WriteLine( i );
}
}
Велика ли разница? :)
Как видите, страшные языковые и библиотечные возможности понадобились для реализации типа самой корутины (IEnumerable в C# - почти полный аналог generator, а Task весьма похожа на нашу future (правда, в полнофункциональном виде пока существующую не в стандарте, а только в реализации Microsoft) ).
В C# опытные программисты тоже реализуют поддержку yield return / await у произвольных типов, и это такая же нетривиальная задача, как в C++.
К сожалению, последний опубликованный language reference по C#, который мне удалось найти — только 5ый, так что сравнить его длину с 9ым не получается по чисто техническим причинам. Впрочем, референс по C# 5 занимает приблизительно 500 страниц, возьмём за отправную точку.
Вроде немного по сравнению с C++ (в документе n4830, например, их уже аж 1802 штуки). Однако в стандарте C++ описан не только язык, но и стандартная же библиотека, в то время как BCL в референсе по языку отсутствует, что довольно логично, но мешает сравнить.
И всё-таки, давайте предметно, пожалуйста. Что именно из новых фич Вы не можете прочитать без боли? Чтобы далеко не бегать, предлагаю обсудить какой-нибудь кусок кода из обсуждаемого цикла статей.
Если хотите уровнять наши страдания, можете тоже предложить мне посмотреть на какой-нибудь кусок кода на шарпах, я попробую рассказать, что кажется неправильным мне =)
Ухх, спасибо огромное за примеры, лично я даже не подозревал о такой подставе с <=> =)
Без нормальных оптимизаций использовать эту штуку вместо операторов сравнения действительно страшновато.
С другой стороны, это детали реализации, рано или поздно вендоры доведут её до ума, и с каждой версией компилятора программы могут становиться быстрее и быстрее, а писать их вполне можно начинать уже сейчас.
> в котором C++20 поддерживается ощутимо лучше. Судя по табличке cppreference.com, там уже почти все фичи реализовали, как библиотечные, так и языковые (хотя недоделки и есть, куда без них).
Честно говоря, тоже ещё не привык думать в стиле c++20, однако при освоении 17ых те же чувства были, правда? Значит, пара месяцев практики — и новой версии начнёт не хватать =)
С поддержкой новых компиляторов, к сожалению, «жиза»… У нас, например, только-только на C++17 переходят, и это не так уж плохо, есть гораздо более консервативные проекты.
А на мой вот взгляд всё с точностью до наоборот, C# сильно раздулся со времен этак пятой редакции, при этом особой лаконичностью там не пахнет.
Ни в коем случае не хочу сказать, что C# хуже C++, а к тому, что для объективного сравнения нужно владеть обоими языками и их стандартными библиотеками в равной мере. Лично я в последнее время отошел от шарпов, и развитие плюсов кажется закономерным и ожидаемым, Вы, видимо, наоборот.
Что же до перетаскивания фичей — так этот процесс со всеми языками идёт, идеи распространяются и эволюционируют.
Ну это Вы зря. На практике с каждой версией стандарта код становится всё лаконичнее и лаконичнее. Другое дело — что с каждой версией разработчикам нужно привыкать к новым фичам.
Оператор трёхстороннего сравнения, std::format, std::ranges, концепты, корутины, даже улучшения в стандартной библиотеке — эти штуки очень здорово упрощают многие существующие куски пользовательского кода, иногда позволяя выкидывать его целыми страницами.
И это если сравнивать код на C++20 и 17. Разница же между C++20 и 98 видна невооруженным взглядом.
Как и с любыми другими наборами инструментов, стандартную библиотеку нужно уметь использовать. Впрочем, за исключением буквально пары языковых фич, не работающих без поддержки со стороны стандартной библиотеке (std::inializer_list, std::type_info, например), использовать std вовсе не обязательно. Можете написать свою, или использовать сторонние.
Вроде у Лукьяненко был только «Мой папа — антибиотик», про сына космодесантника.
А вот очень похожая на сабж история была в рассказе «Мы не рабы» — с тем отличием, что Земля судила колонии, но грозило это в большинстве случаев не экстерминатусом, а серьезными ограничениями.
Мне кажется, проблема в том, что это заставляет много думать ещё и ни в чём не повинных людей, которые будут потом читать и дорабатывать код :) Объявление на месте в современных языках позволяет сузить область видимости переменных и упрощает восприятие программы.
Извините, а рекомендация анализатора N1 точно поможет хоть что-то улучшить? По идее, для вызова конструкторов копирования/перемещения emplace_back и push_back ведут себя практически эквивалентно.
Функция substr вернёт rvalue, push_back практически у всех контейнеров имеет перегрузку, принимающую правостороннюю ссылку, а значит, в контейнер вставится объект всего лишь с двумя вызовами конструктора (внутри substr, и move-конструктор при запихивании объекта в список).
Ну а emplace_back примет аргумент по универсальной ссылке, которая так же преобразуется в rvalue reference, и явно вызовет конструктор копирования с этой ссылкой. То есть опять конструктор внутри substr и move-конструктор.
Попробовал проверить на вот таком вот коде, моё предположение вроде как подтверждается.
С другой стороны, если в коде из предложения N3 optionAreas — это std::vector<fheroes2::Rect>, то здесь emplace_back как раз-таки не помешает, поскольку укоротит код, и позволит действительно создать подобъекты внутри вектора, а не копировать их снаружи.
В код самой игры лезть времени, к сожалению, не было, поэтому контекст не учитывал.
По C++ есть очень интересный цикл C++ Weekly, вдруг кто не видел.
Подавлящее большинство выпусков — 5-20 минутный ликбез по какой-то фиче языка, но есть и исключения.
Автор недавно ещё и книгу выпустил, «C++ Best Practices by Jason Turner»
Нууу, положим, местами гайдлайны мешают сильнее, чем технические ограничения :) С отладкой, подключением библиотек и подобными штуками проблем сейчас действительно нет и быть не должно, но де-факто плюсы получаются и правда «урезанные».
Например, UHT накладывает кучу ограничений на «публичные для движка» хэдеры — нельзя использовать шаблоны, алиасы, private и protected наследование. Узкий выбор контейнеров, и даже не все встроенные контейнеры можно выставить в публичный интерфейс.
Возможности «стандартной библиотеки UE» всё-таки далековаты от возможностей стандартной библиотеки C++. Маловато алгоритмов, некоторые реализованы неоптимально. Эксепшны не должны вылезать за границы пользовательского кода. Нет (во всяком случае, в версии 4.23 не было) прекрасных штук вроде std::string_view, std::variant(на самом деле есть TVariant, но почти не юзабельный), std::exchange. Плохая интеграция с STL, когда всё-таки хочется использовать его под капотом — скажем, нельзя просто так взять и подсунуть контейнер UE4 в алгоритм STL.
Некоторые внутренние механизмы самого движка балансируют на грани Undefined behavior.
Кроме того, в корпоративной среде часто просто принято не использовать заковыристые возможности плюсов (и нет, я не про жуткое шаблонное метапрограммирование), потому что «новичкам, которым потом поддерживать код, это не понять».
Да, никто не мешает использовать всю мощь языка в каких-нибудь глубоко запрятанных системах игровой логики — но ограничения интерфейса создают знатные неудобства. А вообще UE4, конечно, замечательный, расширяемый и очень мощный даже из коробки движок с кучей прекрасных инструментов.
PS: конечно же, всегда хватает мелочей, в которых не разобрался, поленился или просто не дошли руки. А если привыкнуть к философии самого движка, то, возможно, и ощущения нехватки не будет. Но пока некоторых вещей остро не хватает.
Выглядит офигенно красиво, но в видео демонстрируют только маленькую локацию с пустотой за окном. Потянет ли обычная видеокарта(tm) полноценный мир с радиусом видимости в 32 чанка?
Идти к стоматологу, куда ж ещё. Врачи тоже бывают криворукими, и даже самый хороший специалист может совершить ошибку, но, сами понимаете, никто лучше их не умеет чинить ломающуюся тушку.
Вам, видимо, очень не повезло, да ещё и несколько раз подряд, я за всю жизнь побывал у стоматологов раз пятдесят, выдрал шесть зубов (мудрости, которых у меня шесть, а не четыре, как у нормальных людей плюс один обычный), ни раз не было даже сильно больно, не говоря уж о травмах.
Отбросим аргументы шаблона, которые и так дефолтные, ну и заменим unordered_set на set для читаемости:
Если угадать, что делает |x|*n по контексту(как и большинство других конструкций в других языках программирования) может большинство более-менее опытных разработчиков, то для того, чтобы додуматься так написать без примера, нужно обладать ну очень богатой фантазией.
Худшие, по моему очень субъективному и зачастую основанном на слухах в сообществе, мнению, компании, лично я обхожу за версту, и уж точно не думаю о том, чтобы поработать в них.
И вот тут непонятно, ожидается ли, что должен я указать недостоверные подозрения о компании, которую считаю плохой, или отвечать более-менее объективно, но о работодателе, к которому особых претензий не имею?
И ещё — возможно, это какая-то бага в опросе, но о «любимой» компании почему-то не спрашивали ничего, а о «плохой» — дважды просили указать особенности… Вот прям не знаю, что теперь делать…
Хотел только добавить, что Вы зря прибедняете C# насчёт корутин :)
Там они именно что есть, да ещё и в двух разных вариантах, обуславливаемых разными синтаксическими конструкциями - yield return / yield break и await.
Более того, именно из C# корутины приехали в C++, это было предложение Майкрософтов, вдохновлённое наработками из развиваемого ими языка.
Только корутины в C++, будучи развитием уже отработанного подхода, чуть более универсальны: у нас тоже есть три ключевых слова co_yield, co_return и co_await, (на "кококо" все ругаются, но Комитет побоялся использовать для ключевых слов распространённые английские слова, чтобы не ломать обратную совместимость) но по сути это всё - частные случаи оператора co_await.
Так ведь ради краткости и эффективности кода ведь всё и задумывается, причём в эту сторону движутся и C#, и C++, и все остальные языки программирования!
Просто для обеспечения этой простоты и эффективности разработчикам библиотек нужно порой проделать очень немало работы, это относится и к C#, и C++.
Давайте, например, посмотрим на одну из сложнейших языковых фич, корутины: смотрите, вот, к примеру, 250 строк жуткого кода , описание шаблонного типа generator. Без поллитры не разобраться, не правда ли?
Однако это - библиотечный тип, его реализовали один раз опытные люди, и теперь простым смертным достаточно его только использовать:
В C# это выглядело бы примерно так:
Велика ли разница? :)
Как видите, страшные языковые и библиотечные возможности понадобились для реализации типа самой корутины (IEnumerable в C# - почти полный аналог generator, а Task весьма похожа на нашу future (правда, в полнофункциональном виде пока существующую не в стандарте, а только в реализации Microsoft) ).
В C# опытные программисты тоже реализуют поддержку yield return / await у произвольных типов, и это такая же нетривиальная задача, как в C++.
Вроде немного по сравнению с C++ (в документе n4830, например, их уже аж 1802 штуки). Однако в стандарте C++ описан не только язык, но и стандартная же библиотека, в то время как BCL в референсе по языку отсутствует, что довольно логично, но мешает сравнить.
И всё-таки, давайте предметно, пожалуйста. Что именно из новых фич Вы не можете прочитать без боли? Чтобы далеко не бегать, предлагаю обсудить какой-нибудь кусок кода из обсуждаемого цикла статей.
Если хотите уровнять наши страдания, можете тоже предложить мне посмотреть на какой-нибудь кусок кода на шарпах, я попробую рассказать, что кажется неправильным мне =)
Без нормальных оптимизаций использовать эту штуку вместо операторов сравнения действительно страшновато.
С другой стороны, это детали реализации, рано или поздно вендоры доведут её до ума, и с каждой версией компилятора программы могут становиться быстрее и быстрее, а писать их вполне можно начинать уже сейчас.
Судя по табличке cppreference.com, там уже почти все фичи реализовали, как библиотечные, так и языковые (хотя недоделки и есть, куда без них).
Честно говоря, тоже ещё не привык думать в стиле c++20, однако при освоении 17ых те же чувства были, правда? Значит, пара месяцев практики — и новой версии начнёт не хватать =)
С поддержкой новых компиляторов, к сожалению, «жиза»… У нас, например, только-только на C++17 переходят, и это не так уж плохо, есть гораздо более консервативные проекты.
Ни в коем случае не хочу сказать, что C# хуже C++, а к тому, что для объективного сравнения нужно владеть обоими языками и их стандартными библиотеками в равной мере. Лично я в последнее время отошел от шарпов, и развитие плюсов кажется закономерным и ожидаемым, Вы, видимо, наоборот.
Что же до перетаскивания фичей — так этот процесс со всеми языками идёт, идеи распространяются и эволюционируют.
Оператор трёхстороннего сравнения, std::format, std::ranges, концепты, корутины, даже улучшения в стандартной библиотеке — эти штуки очень здорово упрощают многие существующие куски пользовательского кода, иногда позволяя выкидывать его целыми страницами.
И это если сравнивать код на C++20 и 17. Разница же между C++20 и 98 видна невооруженным взглядом.
Как и с любыми другими наборами инструментов, стандартную библиотеку нужно уметь использовать. Впрочем, за исключением буквально пары языковых фич, не работающих без поддержки со стороны стандартной библиотеке (std::inializer_list, std::type_info, например), использовать std вовсе не обязательно. Можете написать свою, или использовать сторонние.
Если хочется попрактиковаться — есть курс от Yandex и МФТИ. Теория доступна любому зарегистрированному пользователю, практика по платной подписке.
Уверен, что есть и другие прекрасные материалы, но эти опробованы на своей шкуре :)
А вот очень похожая на сабж история была в рассказе «Мы не рабы» — с тем отличием, что Земля судила колонии, но грозило это в большинстве случаев не экстерминатусом, а серьезными ограничениями.
Извините, а рекомендация анализатора N1 точно поможет хоть что-то улучшить? По идее, для вызова конструкторов копирования/перемещения emplace_back и push_back ведут себя практически эквивалентно.
Функция substr вернёт rvalue, push_back практически у всех контейнеров имеет перегрузку, принимающую правостороннюю ссылку, а значит, в контейнер вставится объект всего лишь с двумя вызовами конструктора (внутри substr, и move-конструктор при запихивании объекта в список).
Ну а emplace_back примет аргумент по универсальной ссылке, которая так же преобразуется в rvalue reference, и явно вызовет конструктор копирования с этой ссылкой. То есть опять конструктор внутри substr и move-конструктор.
Попробовал проверить на вот таком вот коде, моё предположение вроде как подтверждается.
С другой стороны, если в коде из предложения N3 optionAreas — это std::vector<fheroes2::Rect>, то здесь emplace_back как раз-таки не помешает, поскольку укоротит код, и позволит действительно создать подобъекты внутри вектора, а не копировать их снаружи.
В код самой игры лезть времени, к сожалению, не было, поэтому контекст не учитывал.
Спасибо за статью!
Подавлящее большинство выпусков — 5-20 минутный ликбез по какой-то фиче языка, но есть и исключения.
Автор недавно ещё и книгу выпустил, «C++ Best Practices by Jason Turner»
Например, UHT накладывает кучу ограничений на «публичные для движка» хэдеры — нельзя использовать шаблоны, алиасы, private и protected наследование. Узкий выбор контейнеров, и даже не все встроенные контейнеры можно выставить в публичный интерфейс.
Возможности «стандартной библиотеки UE» всё-таки далековаты от возможностей стандартной библиотеки C++. Маловато алгоритмов, некоторые реализованы неоптимально. Эксепшны не должны вылезать за границы пользовательского кода. Нет (во всяком случае, в версии 4.23 не было) прекрасных штук вроде std::string_view, std::variant(на самом деле есть TVariant, но почти не юзабельный), std::exchange. Плохая интеграция с STL, когда всё-таки хочется использовать его под капотом — скажем, нельзя просто так взять и подсунуть контейнер UE4 в алгоритм STL.
Некоторые внутренние механизмы самого движка балансируют на грани Undefined behavior.
Кроме того, в корпоративной среде часто просто принято не использовать заковыристые возможности плюсов (и нет, я не про жуткое шаблонное метапрограммирование), потому что «новичкам, которым потом поддерживать код, это не понять».
Да, никто не мешает использовать всю мощь языка в каких-нибудь глубоко запрятанных системах игровой логики — но ограничения интерфейса создают знатные неудобства. А вообще UE4, конечно, замечательный, расширяемый и очень мощный даже из коробки движок с кучей прекрасных инструментов.
PS: конечно же, всегда хватает мелочей, в которых не разобрался, поленился или просто не дошли руки. А если привыкнуть к философии самого движка, то, возможно, и ощущения нехватки не будет. Но пока некоторых вещей остро не хватает.