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

Объекты-значения

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

auto a = b + c;
f(a);

Здесь незачем требовать от объекта вызов конструктора перемещения, потому что и так понятно, что этот объект больше нигде не нужен. Всякие RVO и NRVO надо оставить для классов, отмеченных специальным тегом, raii или типа того, а от всех остальных перестать требовать, чтобы они уговаривали компилятор не копировать лишний раз. Не так просто с ходу придумать пример, где бы эти лишние вызовы конструкторов были бы нужны. Может даже концепцию “значения” стоит распространить на вычисление выражений, string("asd") + string("fgh") - здесь ни к чему дёргать конструкторы с деструкторами. А ещё, возможно, так constexpr сможет получаться автоматически.

Очистка стека

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

void f()
{
	...
	long_name(long_expression);
	...
}

получается такой код:

void f()
{
	...
	{
		auto a = long_expression;
		long_name(a);
	}
	...
}

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

Деманглинг имён

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

Библиотека компонентов

Это чуть ли не самое очевидное изменение. Почему у питона есть стандартные прикладные библиотеки типа json, xml и т.д., а когда хочешь прочитать json на C++, надо бегать искать нормальную библиотеку и пытаться подключить. Уже бы сделали standard application library или типа того, чтобы в винду потом складывать sal_crt.dll, sal_xml.dll, sal_json.dll и т.д. В sal_crt проксировать вызовы msvcrt, и тогда не надо будет напрягаться с поддержкой на разных версиях винды. За одно сдуются размеры бинарников, если все будут использовать одни и те же библиотеки. И здесь незачем гнаться за мегаскоростью и т.п., надо сделать стандартный интерфейс с модульной нарезкой, а если кому нужна хитрая мегабыстрая обработка с вызовом мегакривых функций, тогда пусть подключает сторонние библиотеки. Ну и конечно, сами библиотеки должны быть сишными (с нормальными именами функций то есть), глядишь, и другие языки на них пересядут. Пишешь pic install requests и получаешь библиотеку requests с помощью Pack Installer C - удобно же?

Код, запускаемый на этапе компиляции

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

Заполнение на этапе компиляции

float cos_table[100];
compile_time {
for (int i = 0; i < 100; ++i)
	cos_table[i] = std::cos(i);
}

// вычисление на этапе компиляции
struct crc_string {
int value;
crc_string(char* v) {
	compile_time{
		this->value = crc(v);
	}
}
}

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

compile_time {
	auto parser_types = { int, float, std::string };
}

template <class T>
void f(T t)
{
	compile_time {
		// проверка наличия типа в списке
		if (parser_types.contain(T))
			... //какие-то проверки

		// просмотр членов класса
		if (t.members.contain("some_member_name"))
			...
	}
}

Кодогенерация

void g(int t_id, char* value)
{
	switch(type_id(T)) {
		compile_time
		for (c : parser_types) {
			execution_time { // строки в блоке добавить в код
				case type_id(c):
					some_func<T>(value);
					break;
			}
		}
	}
}

Не знаю правда, как это потом отлаживать, но с шаблонами же справились.

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


  1. Melirius
    28.04.2026 12:26

    Гхкм, а что мешает ручному вызову деструктора? "Не идиоматично"?


    1. MegaHard Автор
      28.04.2026 12:26

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


  1. Melirius
    28.04.2026 12:26

    Последнее - это constexpr, constinit и consteval.


    1. MegaHard Автор
      28.04.2026 12:26

      Так об этом и речь. consteval и constinit ведь ввели, чтобы уж точно отработало при компиляции, а не когда-то там. Вот и сделали бы прямое переключение между кодом для исполнения и кодом для компиляции.


      1. HabrSpar
        28.04.2026 12:26

        в рефлексии появился consteval { ... } блок как раз)


        1. MegaHard Автор
          28.04.2026 12:26

          Найти бы ещё его описание. И внутри него можно пройтись по списку типов без шаблонной магии?



          1. j4niwzis
            28.04.2026 12:26

            constexpr auto members = std::array{^^int, ^^char, ^^float};
            auto tup = std::make_tuple(typename [: ...members :]{}...);

            Нечто такое должно быть можно. Есть и template for.


            1. MegaHard Автор
              28.04.2026 12:26

              godbolt.org говорит, что не может разобрать.


              1. j4niwzis
                28.04.2026 12:26

                #include <array>
                
                void foo() {
                  constexpr auto members = std::array{^^int, ^^char, ^^float};
                  template for(constexpr auto t : members) {
                    typename [: t :] x = 0;
                  }
                }

                Вот такой код вполне себе разбирает. https://godbolt.org/z/ec91doMaY


          1. Dooez
            28.04.2026 12:26

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

            Модель объектов C++ наверняка не знаем, но критикуем конструкторы и предлагаем "объекты значения" которые не вызывают конструкторов и что-то делают под капотом.

            Многое из предлагаемого уже можно делать, пусть и не самым эргономичным способом.

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


            1. MegaHard Автор
              28.04.2026 12:26

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

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

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

              которые не вызывают конструкторов

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

              Многое из предлагаемого уже можно делать, пусть и не самым эргономичным способом.

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


              1. eao197
                28.04.2026 12:26

                Странно, если все такие умные, то почему SFINAE устарел, пользовались бы дальше. Или великость помешала сразу нормально сделать

                Возможно, вы еще очень молоды и не застали эпопею с включением концептов в стандарт. Которая была очень долгой и болезненной. Ведь их (концепты) хотели включить еще в C++0x, который в итоге стал C++11 без концептов. А допилили концепты только к C++20.

                Мешала не “великость”, а сложность задачи.


                1. MegaHard Автор
                  28.04.2026 12:26

                  Застал немного время до C++11, в нём потоки, лямбды и прочее удобство добавилось, поэтому чувствовалось, что язык идёт в правильную сторону.


  1. Melirius
    28.04.2026 12:26

    По компонентам есть Boost, там есть всё, но слишком много :)


    1. MegaHard Автор
      28.04.2026 12:26

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

      Как называется dll из boost для работы с json? То-то и оно.


  1. HabrSpar
    28.04.2026 12:26

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

    Деманглинг имён сломает ABI, это наша больная тема(

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

    float cos_table[100];
    compile_time {
    for (int i = 0; i < 100; ++i)
    	cos_table[i] = std::cos(i);
    }

    Про constexpr уже написали, но вот в этом коде может быть не совсем очевидно как сделать, а сделать это можно с помощью IILE:

    #include <algorithm>
    #include <array>
    #include <cmath>
    
    constinit auto cos_table = []() { // constinit не обязателен, но хорошая гарантия
        std::array<float, 100> table;
    
        std::ranges::generate(table, [i = 0] mutable { return std::cos(i++); });
    
        return table;
    }();


    1. MegaHard Автор
      28.04.2026 12:26

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

      Вот и пусть делает.

      Также нет гарантии, что хоть и объект дальше не используется, его можно сразу же переместить и уничтожить.

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

      есть такие проблемы как быстрое реагирование на уязвимости

      Так комитету и не надо над каждой либой сидеть. Я же потому и не в пространство имён std, а в sal их предлагаю. Достаточно обговорить формат и общие правила построения либ, а всё остальное сделать как в pip: не нравится либа - идёшь и накатываешь новую версию.

      Про constexpr уже написали, но вот в этом коде может быть не совсем очевидно как сделать, а сделать это можно с помощью IILE

      Ну вот, начинается брейнфак. И, главное, зачем? Разве мой вариант менее понятный или менее универсальный? Его даже в C можно использовать.


      1. coodi
        28.04.2026 12:26

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


        1. MegaHard Автор
          28.04.2026 12:26

          Давайте пример кода. Отслеживать по упоминанию объекта в коде функции. goto уже не используют, код нынче не столь похож на лапшу. Найти последний блок, в котором было упоминание объекта и можно удалять.


          1. coodi
            28.04.2026 12:26

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


            1. MegaHard Автор
              28.04.2026 12:26

              Тогда он явно не в стэке будет храниться.


  1. j4niwzis
    28.04.2026 12:26

    Может даже концепцию “значения” стоит распространить на вычисление выражений, string("asd") + string("fgh") - здесь ни к чему дёргать конструкторы с деструкторами. А ещё, возможно, так constexpr сможет получаться автоматически.

    Можете тогда предложить свой вариант того, как это могло бы выглядеть? Нужно ведь понимать, что std::string достаточно честный тип, который находится в стандартной библиотеке. Как это совместить со всем остальным в языке? К примеру, с тем же std::vector, std::variant, placement new и ручным управлением времени жизни объекта. constexpr и так получается практически автоматически, достаточно лишь constexpr приписать ко всему (да и if consteval блоки там, где компилятор не может вычислить куски в constexpr, но это более редкий случай).

    Это чуть ли не самое очевидное изменение. Почему у питона есть стандартные прикладные библиотеки типа json, xml и т.д., а когда хочешь прочитать json на C++, надо бегать искать нормальную библиотеку и пытаться подключить.

    Boost уже стал второй стандартной библиотекой. Если не важно то, что сам Boost это достаточно тяжелая зависимость, то можно брать его, хотя и не всё там сделано в самом удобном виде, да и не всё есть.

    Ну и конечно, сами библиотеки должны быть сишными (с нормальными именами функций то есть), глядишь, и другие языки на них пересядут. Пишешь pic install requests и получаешь библиотеку requests с помощью Pack Installer C - удобно же?

    Про имена функций непонятно (буду дальше описывать что если бы Вы предлагали обязать их работать и через C апи в том числе). А что Вы предлагаете делать с библиотеками вроде Boost.Hana, которые целиком на шаблонах сделаны? С таким подходом нельзя будет делать фактически ничего, что делает C++ самим собой. C++ без исключений, шаблонов и constexpr уже сложно назвать C++. С пакетными менеджерами уже давно есть CPM.cmake, да и можно использовать пакетные менеджеры ОС. У некоторых из них возможностей вполне достаточно. К примеру, nix.

    Код, запускаемый на этапе компиляции

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

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

    Уже есть в виде std::meta::info и любых контейнеров, которые умеют хранить значения (к примеру, std::vector). Смотреть рефлексию для C++26.

    Кодогенерация

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

    Хорошо, предположим, что они такие блоки могут возвращать только специальные куски AST. Тогда эта модель с некоторыми изменениями кое-как, но работать может, хотя и сильно сузит возможности для кодогенерации. Но возникает один вопрос зачем это всё? Намного более гибким будет подход с возможностью задать новую функцию/тип/прочее через расширение к compile time рефлексии в C++26 с нужным именем, а после уже определить там тело через типы плюсового AST в стандартной библиотеке (можно и немного сахара для такого придумать, но необязательно).


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


    1. MegaHard Автор
      28.04.2026 12:26

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

      Потому и написал “может”, что это очевидно на стороне пользователя, но не компилятора. Можно предположить такое: если в выражении участвуют POD-типы, то можно посчитать результат и вписать в память. Если используются указатели на POD, то можно так же посчитать результат, выделить память и заполнить.

      достаточно лишь constexpr приписать ко всему

      О том и речь, чтобы не приписывать.

      Boost уже стал второй стандартной библиотекой

      Забиваем в поисковик “как прочитать json в python” и видим предложение использовать стандартный модуль json. Потом там же пробуем “как прочитать json в C++”, и там не видно boost. А ещё могу по второму разу спросить, как в boost называется dll, которая читает json? И да, он тяжёлый, и это проблема. В питоне хоть на маке, хоть на винде импортируешь нужную либу через pip и в продакшен. То есть вопрос не в возможности как таковой, а в пользовательском опыте. C++ просто неудобно пользоваться.

      А что Вы предлагаете делать с библиотеками вроде Boost.Hana, которые целиком на шаблонах сделаны?

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

      Так и не ясно, чем это было бы лучше подхода с constexpr сейчас

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

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

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

      Можно было бы изучить вопрос получше, а не сразу выкидывать про это на Хабр?

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


      1. j4niwzis
        28.04.2026 12:26

        Потому и написал “может”, что это очевидно на стороне пользователя, но не компилятора. Можно предположить такое: если в выражении участвуют POD-типы, то можно посчитать результат и вписать в память. Если используются указатели на POD, то можно так же посчитать результат, выделить память и заполнить.

        А можно увидеть какое-то более подробное описание алгоритма? И какое отношение имеет std::string к POD типам?

        О том и речь, чтобы не приписывать.

        Суть в чём? Чтобы функция могла считаться constexpr по умолчанию? Но подозреваю, что могут возникнуть некоторые проблемы.

        Забиваем в поисковик “как прочитать json в python” и видим предложение использовать стандартный модуль json. Потом там же пробуем “как прочитать json в C++”, и там не видно boost. А ещё могу по второму разу спросить, как в boost называется dll, которая читает json? И да, он тяжёлый, и это проблема. В питоне хоть на маке, хоть на винде импортируешь нужную либу через pip и в продакшен. То есть вопрос не в возможности как таковой, а в пользовательском опыте. C++ просто неудобно пользоваться.

        Зачем мне знать про какие-то там dll-ки? Какое отношения они вообще имеют к вопросу? Опять же, существуют CPM.cmake и nix, с которыми подключить библиотеку дело достаточно быстрое и удобное.

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

        Предлагаете тогда не закидывать туда огромную кучу нормальных библиотек, а оставить только библиотеки без шаблонов? К примеру, Boost.Asio много использует шаблоны достаточно много, range-v3, ctre и т.д.

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

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

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

        Не наблюдаю тут никакой прозрачности. Можете рассказать про неё подробнее?

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

        На что ниже у меня там тоже есть свой комментарий.


        1. MegaHard Автор
          28.04.2026 12:26

          А можно увидеть какое-то более подробное описание алгоритма? И какое отношение имеет std::string к POD типам?

          Мне как-то приходилось компилятор править, так что при некотором желании можно, но сейчас наверное нет смысла. В компиляторе же есть упрощение выражений, состоящих из констант, типа (4+5)*6. Некоторая интерпретация кода вроде тоже есть. Тут конечно вопрос, как добраться до кода функций, остаётся полагаться на то, что они в заголовочном файле.
          std::string хоть и не pod, но в ней какие-то инты и указатель на массив pod’ов, можно и это попробовать проинтерпретировать.

          Зачем мне знать про какие-то там dll-ки? Какое отношения они вообще имеют к вопросу?

          Какое отношение динамические библиотеки имеют к вопросу о стандартных библиотеках? Даже не знаю. Расслабились все, место на диске не жалеют. Скачал clang, а там пачка почти одинаковых exe’шников по 100 с лишним мегабайт весом.

          Опять же, существуют CPM.cmake и nix

          Что-то узкоспециализированное. nix вообще с трудом гуглится. Если речь про язык программирования, то говорить, что в C++ что-то есть, ссылаясь на другой язык, ну не знаю.

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

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

          Зачем вообще он нужен будет тогда

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


          1. j4niwzis
            28.04.2026 12:26

            Мне как-то приходилось компилятор править, так что при некотором желании можно, но сейчас наверное нет смысла. В компиляторе же есть упрощение выражений, состоящих из констант, типа (4+5)*6. Некоторая интерпретация кода вроде тоже есть. Тут конечно вопрос, как добраться до кода функций, остаётся полагаться на то, что они в заголовочном файле. std::string хоть и не pod, но в ней какие-то инты и указатель на массив pod’ов, можно и это попробовать проинтерпретировать.

            Как Вы это в стандарт описывать собираетесь? И зачем так делать?

            Какое отношение динамические библиотеки имеют к вопросу о стандартных библиотеках? Даже не знаю. Расслабились все, место на диске не жалеют. Скачал clang, а там пачка почти одинаковых exe’шников по 100 с лишним мегабайт весом.

            Так дело в том, что мне вообще нет дело до dll-ек. Я подключаю библиотеку в CMake, а дальше уже само находит и подключает. До уровня .dll опускаться смысла нет.

            Что-то узкоспециализированное. nix вообще с трудом гуглится. Если речь про язык программирования, то говорить, что в C++ что-то есть, ссылаясь на другой язык, ну не знаю.

            Nix это не только язык, но ещё и ОС и пакетный менеджер. nixos.org.

            CPM.cmake это просто вспомогательные cmake скрипты для подключения пакетов. Используется, к примеру, в userver. https://github.com/cpm-cmake/CPM.cmake

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

            Вы так и не ответили на то, а зачем нужно такое с C апи?


            1. MegaHard Автор
              28.04.2026 12:26

              Как Вы это в стандарт описывать собираетесь? И зачем так делать?

              Ни разу не пробовал, так что не знаю. А делать так для оптимизации кода. Возможно, стандарт должен разрешить дополнительно оптимизировать код для объектов без тега. Примерно как с volatile, если переменная помечена таким тегом, тогда все чтения и записи делаем скурпулёзно, а если нет, то оптимизируем.

              Так дело в том, что мне вообще нет дело до dll-ек. Я подключаю библиотеку в CMake, а дальше уже само находит и подключает. До уровня .dll опускаться смысла нет.

              После чего пользователи начинают жаловаться, что у них dll не хватает. Или, допустим, запускаешь свою прогу, а она подхватывает dll от notepad++ и делает что-то не то.

              Вы так и не ответили на то, а зачем нужно такое с C апи?

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


              1. j4niwzis
                28.04.2026 12:26

                Ни разу не пробовал, так что не знаю. А делать так для оптимизации кода. Возможно, стандарт должен разрешить дополнительно оптимизировать код для объектов без тега. Примерно как с volatile, если переменная помечена таким тегом, тогда все чтения и записи делаем скурпулёзно, а если нет, то оптимизируем.

                Стандарт и так разрешает оптимизировать код. Компилятор имеет право вырезать лишние конструкторы, деструкторы и прочее. Только есть разница в том, что считается наблюдаемыми эффектами. Если аллокации такими не считать, то компилятор будет иметь право работать и с длинными std::string (когда не срабатывает SSO).

                После чего пользователи начинают жаловаться, что у них dll не хватает. Или, допустим, запускаешь свою прогу, а она подхватывает dll от notepad++ и делает что-то не то.

                Первый раз слышу про такие проблемы. Но у меня и с виндой опыта разработки нет, 100% кода пишу на лине.

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

                Не такое уж и значительное преимущество.


      1. HiItsYuri
        28.04.2026 12:26

        Вы за 10 лет не осилили прочесть "The Design and Evolution of C++"? После ее прочтения обычно половина таких вопросов отпадает.


        1. MegaHard Автор
          28.04.2026 12:26

          Эхе-хе, помню, в 17 стандарте вроде что-то про инициализацию переменных добавили, в 20 обратно откатили. Ещё меня как-то попросили дать ссылку на хороший код. Полез в исходники clang’а, а там такие нечитабельные трёхэтажные выражения, с целью оптимизации наверное. Да и вообще оказалось, что красивый код сложно найти. После такого вопросы, наоборот, возникают )


          1. HiItsYuri
            28.04.2026 12:26

            Сложные вещи не всегда можно написать просто.

            А красота тут вообще ортогональна.


  1. RootTool
    28.04.2026 12:26

    Про генерацию кода во время компиляции - это уже отдельный этап Compile-time, который явно появился в Zig (Comptime называется)

    А по библиотеке компонентов - было бы неплохо читать JSON/XML и другие конфиг форматы во время компиляции, и заполнять структуры и тд. Удобная штука на самом деле, но опять же "никакая строка не должна быть переписанная, будь она написана в 1986 или 2026"

    От себя могу добавить как идею (хотя я уже потихоньку это реализовываю для своего движка) - делать public/protected поля с указанием кому именно они относятся. Пример: "public(FRenderer, FPhysics): ....". И тогда поле как бы является публичным, но только если обращение идет из класса/структуры FRenderer или FPhysics. Получается такой своеобразный "умный friend" (так как мы не раскрываем прям все поля и методы, как это делает обычный friend)


  1. pavlushk0
    28.04.2026 12:26

    Странный поток мысли. Какой учёт конструкторов? Кто его ведёт? Ничего непонятно. Рво нрво выполняется автоматически компилятором. Кто требует пепемещения? Наверно тот же кто ведет учет конструкторов... чем человеку скобочки не угодили? Как вызывать конструкторы раньше? Наверно отделной языковой конструкцией! Давайте добавим) хотя есть delete и явный вызов. Большая часть батареек питона давно села, для джейсона либ хоть попой жуй, с десятками тысяч звёзд, тут уж каждый первый c++ задрот считает делом чести поабъюзить сфине. Про constexpr я вообще ничего не понял...


    1. MegaHard Автор
      28.04.2026 12:26

      Рво нрво выполняется автоматически компилятором.

      Там вполне конкретный код приведён, и там RVO/NRVO не применяется, была по этому поводу на Хабре статья.

      чем человеку скобочки не угодили

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

      для джейсона либ хоть попой жуй

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


      1. HiItsYuri
        28.04.2026 12:26

        Попробуйте ответить на вопрос, почему они продолжают плодиться

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

        У меня была ситуация, когда я не мог использовать "стандартный" в проекте сериализатор в json, потому что он в потоковую запись не умел.

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


        1. MegaHard Автор
          28.04.2026 12:26

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

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


          1. HiItsYuri
            28.04.2026 12:26

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


            1. MegaHard Автор
              28.04.2026 12:26

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


              1. j4niwzis
                28.04.2026 12:26

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


                1. MegaHard Автор
                  28.04.2026 12:26

                  Согласен.


      1. pavlushk0
        28.04.2026 12:26

        Кокретный код это вот тут?

        auto a = b + c;
        f(a);

        А где тут вообще (N)RVO кейс мог бы быть?

        Зачем какието теги для (N)RVO если это оптимизация на усмотрение компилятора (на чиная с 17 даже строже)? Зачем её явно запрещать или разрешать? Конструкторы и RVO это перпендикулярные вещи.

        Мажорных либ 2 - rapidJson и nlohmannjson. В Qt своя хорошая реализация.


        1. ZirakZigil
          28.04.2026 12:26

          Конструкторы и RVO это перпендикулярные вещи.

          Ну как же. (N)RVO это copy elision, что с конструкторами связано настолько прямо, настолько возможно. Выражение (N)RVO как таковое в стандарте вообще не используется.


        1. MegaHard Автор
          28.04.2026 12:26

          А где тут вообще (N)RVO кейс мог бы быть?

          Ни где, и вроде даже не утверждается ни где, что он мог бы быть. Речь о том, чтобы компилятор, если он видит, что один из объектов дальше использоваться не будет, не создавал копию, а использовал оригинал, не думая о том, что возможно, программист действительно хотел получить вызов копирующего конструктора. Пойдите и посчитайте, сколько раз в проекте вызывается std::move, в удобном языке должно быть в районе 0.

          Зачем какието теги для (N)RVO если это оптимизация на усмотрение компилятора (на чиная с 17 даже строже)? Зачем её явно запрещать или разрешать? Конструкторы и RVO это перпендикулярные вещи.

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


  1. apevzner
    28.04.2026 12:26

    Наконец, хотя этот предмет не из приятных, я должен упомянуть PL/1, язык программирования, документация которого обладает устрашающими размерами и сложностью. Использование PL/1 больше всего напоминает полет на самолете с 7000 кнопок, переключателей и рычагов в кабине. Я совершенно не представляю себе, как мы можем удерживать растущие программы в голове, когда из-за своей полнейшей вычурности язык программирования — наш основной инструмент, не так ли! — ускользает из-под контроля нашего интеллекта. И если мне понадобится описать влияние, которое PL/1 может оказывать на своих пользователей, ближайшее сравнение, которое приходит мне в голову, — это наркотик. Я помню лекцию в защиту PL/1, прочитанную на симпозиуме по языкам программирования высокого уровня человеком, который представился одним из его преданных пользователей. Но после похвал в адрес PL/1 в течение часа он умудрился попросить добавить к нему около пятидесяти новых “возможностей”, не предполагая, что главный источник его проблем кроется в том, что в нем уже и так слишком уж много “возможностей”. Выступающий продемонстрировал все неутешительные признаки пагубной привычки, сводящейся к тому, что он впал в состояние умственного застоя и может теперь только просить еще, еще, еще. Если FORTRAN называют детским расстройством, то PL/1, с его тенденциями роста подобно опасной опухоли, может оказаться смертельной болезнью.

    Э.Дейкстра, Смиренный программист, 1972


    1. j4niwzis
      28.04.2026 12:26

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

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


      1. apevzner
        28.04.2026 12:26

        Я считаю Go прекрасным языком.

        И нет, это не мой первый язык, и я отнюдь не новичок в профессии.


        1. eao197
          28.04.2026 12:26

          Я считаю Go прекрасным языком.

          Ключевое здесь “я”.

          И нет, это не мой первый язык, и я отнюдь не новичок в профессии.

          Есть ненулева вероятность, что вы просто все это время работаете над проектами, в которых более чем достаточно Си или Go. И, как следует из множества разговоров с вами (что здесь, то на RSDN), C++а вы и не знаете, особенно современного. Но мнение имеете и старательно его доносите до окружающих, хотя C++ вас использовать никто не заставляет. Оставили бы вы C++ для тех, кто (в отличии от вас) не хочет пердолиться с Си.


    1. MegaHard Автор
      28.04.2026 12:26

      Угадайте, в каком языке форматирование делается так же, как в std::format. Часть пунктов направлена скорее на упрощение, чем на усложнение, чтобы не тратить ману на расстановку std::move, например.


      1. apevzner
        28.04.2026 12:26

        Угу. Ещё скажите, что Питон - простой язык.


        1. MegaHard Автор
          28.04.2026 12:26

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


          1. apevzner
            28.04.2026 12:26

            А если что-то чуть более серьёзное, то внезапно выясняется, что у него система типов сложнее, чем у C++


  1. AHL
    28.04.2026 12:26

    В чем проблема, сваять очередную версию С в которой будет всё перечисленное.

    Кто мешает тебе выдумать порох непромокаемый? (С)


  1. Jijiki
    28.04.2026 12:26

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

    #include <std> //пространство базовое
    import <string>// импорт наполняет пространство возможностями, базовое пространство не надо прописывать
    //всё функции, убрать воид, и указывать явно тип если он нужен
    class Test{
      int a;
      Test(){
        //constructor()  
      }
      
      ~Test{
        //autodestructor()
      }
    }
    
    class Test1<T>{
      int b;
      Test1(){
        //constructor()  
      }
      
      ~Test1{//сделать тильду невызываемую, а брекетом автоудаление после выхода
        //autodestructor()
      }
    }
    
    
    int main(){
      auto a = Test::Test();
      auto b = Test1::Test1<int>();
      return 0;
    }

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


    1. SilverTrouse
      28.04.2026 12:26

      c++23 import std;


  1. wingooey
    28.04.2026 12:26

    Может быть переключитесь на Rust, многабукафнечитал, но как будто там почти всё вышеописанное сделано удобно, а не неудобно как в c++ =)


    1. j4niwzis
      28.04.2026 12:26

      Раст сам по себе не лучший язык. Даже шаблонов из C++ нет. Вся работа с кодогенерацией работает через его макросы, которые работают с текстом, а не с типами. Всё ли в расте с аналогом constexpr хорошо? https://godbolt.org/z/sn3cbPYKz и даже не заифать https://godbolt.org/z/TGaGPP37c

      В расте нет и исключений (они как-бы есть в виде паник, но кто их применяет везде?).

      Перегрузок в расте нет.

      Рефлексии в расте тоже нет, когда в плюсах она есть.