LINUX.ORG.RU

Современно современный C++

 ,


1

4

Под современным C++ обычно подразумевают C++11. Вышедшие после него C++14 и C++17 обычно называют минорными обновлениями стандарта. И вот, с появлением C++20, а недавно и C++23 появился современно современный C++. Тавтология по аналогии с long long.

Так вот, читаю сейчас совсем свежую книгу Beginning C++23 From Beginner to Pro, седьмое издание, авторы Ivor Horton и Peter Van Weert. Книга учит программированию на C++23 и довольно неклассическим образом. Вот самая первая программа из неё:

// Ex1_01.cpp - A complete C++ program
import std;          // This line makes the entire Standard Library available,
                     // including the std::println() functionality used below

int main()
{
  int answer {42};   // Defines the variable answer with value 42
  std::println("The answer to life, the universe, and everything is {}.", answer);
  return 0;
}

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

exercise 1-1. Create, compile, link, and execute a program that will display the text «Hello World» on your screen.

exercise 1-2. Create and execute a program that outputs your name on one line and your age on the next line. define a variable to hold your age first.

exercise 1-3. the following program produces several compiler errors. Find and correct these errors so the program compiles cleanly.

#import std
Int main
{
  std:printn("Holla Mundo!")
)

Так же в первых главах авторы написали:

As of C++23, the preferred mechanism for outputting text to the computer’s screen is through functions such as std::println() and std::print(). We will use these in nearly every example in this book.

Короче C++23 начинает напоминать Java. Но эту тему я открыл не поэтому. Мне вот стало интересно, а как воспримут обучившегося по такой книге джуна или мидла матёрые си плюс плюснутые дядьки из реальных проектов? Вот придёт такой свежеобученный программист в реальный проект и начнёт проталкивать C++ модули везде и всюду. Что скажут старшие товарищи? Побьют или они уже и сами перешли на модули и пишут свой код так, как описано в этой книге?

Не поймите меня неправильно, в книге рассказывают и о классических стримах ввода/вывода, но даже там говорят, что std::print() и std::println() предпочтительнее:

Streams

Input and output in C++ are, as a rule, performed using streams. To output data, you write it to an output stream, and to input data, you read it from an input stream. A stream is an abstract representation of a source of data or a data sink. When your program executes, each stream is tied to a specific device that is the source of data in the case of an input stream and the destination for data in the case of an output stream. The advantage of having an abstract representation of a source or sink for data is that the programming is then the same regardless of the device the stream represents. You can read a disk file in essentially the same way as you read from the keyboard.

std::print() and std::println() are little more than thin layers on top of streams. In essence, the std::println() statement in the main() function of Ex1_01 is analogous to either one of these statements:

std::cout << std::format("The answer to life, the universe, and everything is {}.", answer) << std::endl;
std::cout << "The answer to life, the universe, and everything is " << answer << std::endl;

The standard output and input streams in C++ are called std::cout and std::cin, respectively, and by default, they correspond to your computer’s screen and keyboard. You’ll be reading input from std::cin in Chapter 2 and later chapters.

std::format() is similar to std::print(), except that instead of streaming directly to the standard output stream, std::format() returns the formatted character sequence encapsulated in a std::string object (see Chapter 7). This is why std::print() is effectively analogous to streaming the result of std::format() to std::cout, as we did in the first line of our example.

<<, finally, is the stream insertion operator that transfers data to a stream. In Chapter 2, you’ll meet the stream extraction operator, >>, which similarly reads data from a stream. Whatever appears to the right of each << is transferred to std::cout. You can insert as many strings or other values in one statement as you want (we’ll clarify how this works exactly in Chapter 13). Inserting std::endl to std::cout causes a new line to be written to the stream and the output buffer to be flushed. Flushing the output buffer ensures that the output appears immediately.

Compared to working directly with std::cout, working with std::print() and std::println() is generally both more elegant and efficient (see the next chapter for more convincing evidence). This is why we won’t use output streams that often anymore as of this edition of the book. But because output streams remain an important concept in C++ in general, we’ll briefly return to working with streams at the end of the next chapter to introduce the basic principles.

Разумеется, большинство настоящих проектов на C++ заняты вовсе не вводом/выводом в консоль. Но переход на модули наверняка меняет устоявшиеся привычки в программировании на C++ ещё во множестве других мест. Мне интересно, как это будет воспринято синьёрами помидорами? Помню как я сам начинал программировать на Java в 2006 году. Во время обучения я использовал Java 6, в которой был новый синтаксис цикла for. На собеседовании у меня был лайв кодинг и когда я начал писать такой цикл и написал двоеточие интервьюирующий меня груплид воскликнул: «это же не Pascal!» В тогдашнем проекте той конторы использовали Java 5, в которой for-each только появился.



Последнее исправление: zg (всего исправлений: 1)

И вот, с появлением C++20, а недавно и C++23 появился современно современный C++.

Да он не совсем и появился, только появляется. GCC до сих пор не полностью реализовал стандарт языка 20, а у шланга ещё и 17.

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

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

Но переход на модули наверняка меняет устоявшиеся привычки в программировании на C++ ещё во множестве других мест.

Если кодобазу будет муторно переводить на модули, то просто не станут и всё тут.

На собеседовании у меня был лайв кодинг и когда я начал писать такой цикл и написал двоеточие интервьюирующий меня груплид воскликнул: «это же не Pascal!»

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

Bfgeshka ★★★★★
()
Ответ на: комментарий от Bfgeshka

Да он не совсем и появился, только появляется. GCC до сих пор не полностью реализовал стандарт языка 20, а у шланга ещё и 17.

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

Clang уже полностью поддерживает C++17, а поддержка модулей частичная https://clang.llvm.org/cxx_status.html

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

А причём тут C++11? Тут как минимум C++20.

zg
() автор топика
Последнее исправление: zg (всего исправлений: 1)
Ответ на: комментарий от zg

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

Верю, но в дикой природе не всегда как в книге :)

Clang уже полностью поддерживает C++17, а поддержка модулей частичная https://clang.llvm.org/cxx_status.html

Любопытно, я вот тут глядел: https://en.cppreference.com/w/cpp/compiler_support/17 Кто-то где-то врёт.

А причём тут C++11? Тут как минимум C++20.

Потому что большое разделение крестовиков было где-то в 11 и 14.

Bfgeshka ★★★★★
()

Мне интересно, как это будет воспринято синьёрами помидорами?

проекты пишутся под определенные заказы от бизнеса, и определенные системы Linux, на которых версия gcc даже еще не понимает -std=c++20.

anonymous2 ★★★★★
()
Ответ на: комментарий от zg

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

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

anonymous
()

Модули — хрень. Нет систем сборки. Не работают макросы. Ни одна библиотека их не использует — стало быть в проекте будут # include. И смысл в модулях преподаёт полностью.

А «профессионализм» ISO'шников только и позволяет им print изобретать заново.

zx_gamer ★★★
()

начнёт проталкивать C++ модули везде и всюду

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

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

a1ba ★★
()

в книге рассказывают и о классических стримах ввода/вывода, но даже там говорят, что std::print() и std::println() предпочтительнее

То есть, до стандартописателей таки дошло, что плюсовыми потоками никто, кроме фанатиков, не пользовался, и они запилили printf++?

alegz ★★★★
()
Ответ на: комментарий от anonymous

Да проблема в том, то cout не умеет форматировать вывод нигде даже близко с printf, там только фича типопофигизма, а оно не так и важно для людей помимо auto лодырей.

Bfgeshka ★★★★★
()
Ответ на: комментарий от Bfgeshka

cout не умеет форматировать вывод

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

что ещё?

там только фича типопофигизма, а оно не так и важно для людей помимо auto лодырей

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

anonymous
()

Не поможет, плюсы теперь депрекейтед, если бы лет 20 назад сделали модули с нормальными макросами и системой типов, а заодно выкинули бы сишку, убрали UBшные завалы, починили синтаксис наконец - ещё бы походило

zurg
()
Последнее исправление: zurg (всего исправлений: 1)
Ответ на: комментарий от alegz

То есть, до стандартописателей таки дошло, что плюсовыми потоками никто, кроме фанатиков, не пользовался, и они запилили printf++?

Запилить-то они запилили. Но как-то так вышло, что определить для своего типа operator<< для std::ostream сильно проще, чем сделать специализацию std::formatter.

Так что здесь, как это часто бывает в C++, «хотели как лучше, а получилось как всегда» (с)

eao197 ★★★★★
()
Ответ на: комментарий от zg

Кем депрекейтед

индустрией, гуглы не по капризу гошечки изобретает, и самими плюсовиками - Carbon и какой-то C++2 от самого Саттера

что взамен

сейчас? да что угодно, для системщины и около неё очевидны Rust, Ada и может Zig, это тогда только D был, а ада илитарненько в своей военке отсиживалась, без тулинга, без библиотек и документации

zurg
()
Ответ на: комментарий от zurg

какой-то C++2 от самого Саттера

Саттер колупается с cppfront для того, чтобы экспериментировать с новыми идеям для C++. Он вроде как не озвучивал намерений превратить свой cppfront в новый язык программирования пригодный для промышленной эксплуатации.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

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

zurg
()
Последнее исправление: zurg (всего исправлений: 1)

Вот самая первая программа из неё

и где настройки локали ? :-) println выдаст в поток \n \n\r или что-то ещё ??

а вообще где-то на просторах был шуточный пример: helloword.c сделанный по всем-правилам правилам си и гну. Не совсем маленький проект вышел...

MKuznetsov ★★★★★
()
Ответ на: комментарий от zurg

по объективным показателям плюсы по прежнему в пределах топ-3/топ-5 востребованности, а икспертные сотрясания воздуха с батхёртами интересны только журнализдам и блогеркам

anonymous
()
Ответ на: комментарий от Bfgeshka

Clang уже полностью поддерживает C++17, а поддержка модулей частичная https://clang.llvm.org/cxx_status.html

Любопытно, я вот тут глядел: https://en.cppreference.com/w/cpp/compiler_support/17 Кто-то где-то врёт.

К примеру Parallel algorithms Clang еще не поддерживает в полной мере - столкнулись в реальной жизни с этим

alex-w ★★★★★
()
Ответ на: комментарий от eao197

Белый Дом Престарелых

Исправил, не благодари.

Java, C#, Rust, например.

Ну Rust я ещё могу понять. Но Java и C# (та же Java по сути), тут каким боком вообще? Всё что они могли отнять у C++ они уже отняли лет 20 назад и ничего больше отнять не смогут. Говорю, как опытный Java разработчик.

zg
() автор топика
Ответ на: комментарий от eao197

Запилить-то они запилили. Но как-то так вышло, что определить для своего типа operator<< для std::ostream сильно проще, чем сделать специализацию std::formatter.

А если в разных местах нужно по-разному форматировать вывод одного и того же типа? И твой подход сильно нарушает single responsibility. Глобально переопределять operator<< ради форматирования вывода в консоль - это начало поиска проблем.

zg
() автор топика
Ответ на: комментарий от MKuznetsov

а вообще где-то на просторах был шуточный пример

Это не совсем шуточный пример в отличие от джавовского FizzBuzz Enterprise Edition. Там главная цель: показать образец проекта. Непосредственно кода там немного, и он связан в основном с обработкой ключей командной строки: https://github.com/rajeshsola/gnu-hello/blob/master/src/hello.c

static_lab ★★★★★
()
Ответ на: комментарий от zurg

индустрией, гуглы не по капризу гошечки изобретает, и самими плюсовиками - Carbon и какой-то C++2 от самого Саттера

Go был взят почти готовым из Plan9. Полноценной заменой C++ он не является, хотя кое где действительно может потеснить C++. Что касается Carbon и C++2 - это не более чем эксперименты и в серьёзных проектах использовать их будут разве что маргиналы.

zg
() автор топика
Ответ на: комментарий от zg

А если в разных местах нужно по-разному форматировать вывод одного и того же типа?

Вопрос в том, что значит «по-разному»?

Если «по-разному» означает выравнивание в рамках поля в 40 символов, то это одно. В том же fmtlib, емнип, это решается тем, что в форматной строке ты задаешь ширину поля и выравнивание, а сам объект заворачиваешь в fmt::streamed. И все.

Если «по-разному» означает применение форматов чисел (десятичное, шестнадцатиричное, двоичное и т.д.), то тут, вообще-то, нехилая засада. Допустим, у меня свой тип, в котором есть вектор int-ов, вектор float-ов и еще пара-тройка std::uint8_t. Захардкодить вывод того всего в std::ostream – ну вот как два пальца. А вот сделать так, чтобы в std::print/format для моего типа можно было задать формат для int-ов и float-ов… Ну разве что можно пожелать удачи такому мазохисту.

eao197 ★★★★★
()
Ответ на: комментарий от zg

Для меня operator<< – это удобный способ отображать объекты моих типов на консоль или в лог-файл. Преобразование в строку – это частный случай такой операции.

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

class my_type {...};

// Отображение по умолчанию.
std::ostream &
operator<<(std::ostream & to, const my_type & what) { ... };

// Обертка для специфического отображения my_type.
struct my_type_in_hex {
  const my_type & m_what;
};
// Отображение my_type в hex-представлении.
std::ostream &
operator<<(std::ostream & to, const my_type_in_hex & what) { ... };

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

Так что позвиздеть на форуме, наверное, можно. Где-то в продакшене такое встретить… Это вряд ли.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

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

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

zg
() автор топика
Ответ на: комментарий от zg

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

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

eao197 ★★★★★
()

Мне интересно, как это будет воспринято синьёрами помидорами?

А сам-то как думаешь? Зависит от команды, конечно же. Где-то помидоры застыли в развитии настолько что «под современным C++ подразумевают C++11», где-то llvm trunk, по умолчанию 2[xyz] (который следующий) и ещё часть пропозалов руками реализована.

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

Но переход на модули наверняка меняет устоявшиеся привычки в программировании на C++ ещё во множестве других мест

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

bool all_matching = true;
for (const auto& item: collection) {
    if (!pred(item)) {
        all_matching = false;
        break;
    }
}

можно заменить на none_of(collection, pred), а для кого-то вообще что чтобы сет зааппендить в вектор не нужно писать цикл.

anonymous
()