Re[11]: Полухин - что там с С++26
От: B0FEE664  
Дата: 13.01.26 09:39
Оценка:
Здравствуйте, Went, Вы писали:

W>Ну в этом же и суть, что в интерполяции нет разбора строки на этапе исполнения. То есть это ни в коем случае не сахар поверх format, а наиболее оптимальный из возможных способ сборки строки из базы и плейсхолдеров, потому что всё то, что можно, компилятор может вытянуть на этапе компиляции.

Что можно собрать на этапе компиляции? Только то, что фиксированного размера в выводе. Так что строки и числа не фиксированной длины отпадают. Например:
std::string str = std::format("a = {var} - ok");

особо оптимизировать не получится. Если var, скажем, int, то он может быть и 4 и 444. А значит в результирующую строку всё равно придётся складывать минимум из двух частей: "a = 444" и " — ok". То есть на каждую числовую переменную теоретически можно сэкономить одну операцию конкатенации строк. А если var — это строка, то сэкономить уже ничего не получится. Однако я сильно сомневаюсь, что кто-то будет заниматься такой мелочной оптимизацией.

W>std::format же принципиально другой подход, напротив, где оптимальность уступается в угоду гибкости (например, в разных локализациях плейсхолдеры могут идти в разном порядке). О чем же мы спорим?

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

Короче, можете объяснить: где вы предполагаете возможность оптимизации?
И каждый день — без права на ошибку...
Re[12]: Полухин - что там с С++26
От: Went  
Дата: 22.01.26 07:45
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Короче, можете объяснить: где вы предполагаете возможность оптимизации?

Выражение $"Get {count} of {fruit}.".
По отношению к конкатенации ("Get " + std::to_string(count) + " of " + fruit + ".") — нет необходимости многократно перевыделять буферы и копировать.
По отношению к форматированию (std::format("Get {0} of {1}", count, fruit)) — нет необходимости парсить строку на этапе исполнения, нет необходимости создавать обобщенный механизм под произвольное количество аргументов-плейсхолдеров; все разворачивается в линейный код: сконвертили в строки все не строки (хотя для чисел можно взять максимум и конвертить уже in-place), оценили суммарный размер буфера, выделили один раз строку нужной длины, скопировали всё один раз.

Даже если сделать constexpr-версию std::format, где первый аргумент разбирается на этапе компиляции, то я очень сомневаюсь, что оптимизатор компилятора сможет превратить эту шаблонную магию в что-то соизмеримое с тем, что напишут разработчики компилятора.
Re[13]: Полухин - что там с С++26
От: sergii.p  
Дата: 22.01.26 11:37
Оценка:
Здравствуйте, Went, Вы писали:

W>Даже если сделать constexpr-версию std::format, где первый аргумент разбирается на этапе компиляции, то я очень сомневаюсь, что оптимизатор компилятора сможет превратить эту шаблонную магию в что-то соизмеримое с тем, что напишут разработчики компилятора.


сделать то можно. Та же библиотека fmt такое делает и работает ощутимо быстрее. В STL видимо других проблем хватает.
Хотя не исключаю, что std::format доведут до ума. Эта функциональность молодая ещё, подождём годков 10...
Re[5]: Полухин - что там с С++26
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.01.26 07:16
Оценка:
Здравствуйте, Hоmunculus, Вы писали:

BFE>>А зачем?

BFE>>Чем это лучше:

H>Тем что форматипованную строку можно целиком сохранить, например для переводчиков, и потом целиком же единую строку и выводить, а не разбивать на кучу подстрок


Единственная проблема — std::format принимает строки времени компиляции, и не работает с рантайм форматными строками
Маньяк Робокряк колесит по городу
Re[11]: Полухин - что там с С++26
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.01.26 07:18
Оценка:
Здравствуйте, Went, Вы писали:

W>Ну в этом же и суть, что в интерполяции нет разбора строки на этапе исполнения. То есть это ни в коем случае не сахар поверх format, а наиболее оптимальный из возможных способ сборки строки из базы и плейсхолдеров, потому что всё то, что можно, компилятор может вытянуть на этапе компиляции. std::format же принципиально другой подход, напротив, где оптимальность уступается в угоду гибкости (например, в разных локализациях плейсхолдеры могут идти в разном порядке). О чем же мы спорим?


Чем же подход std::format принципиально другой, когда он тоже на этапе компиляции работает?
Маньяк Робокряк колесит по городу
Re[12]: Полухин - что там с С++26
От: Went  
Дата: 23.01.26 15:38
Оценка:
Здравствуйте, Marty, Вы писали:

M>Здравствуйте, Went, Вы писали:


W>>Ну в этом же и суть, что в интерполяции нет разбора строки на этапе исполнения. То есть это ни в коем случае не сахар поверх format, а наиболее оптимальный из возможных способ сборки строки из базы и плейсхолдеров, потому что всё то, что можно, компилятор может вытянуть на этапе компиляции. std::format же принципиально другой подход, напротив, где оптимальность уступается в угоду гибкости (например, в разных локализациях плейсхолдеры могут идти в разном порядке). О чем же мы спорим?


M>Чем же подход std::format принципиально другой, когда он тоже на этапе компиляции работает?

В неком пределе оптимальности шаблонного кода и качества оптимизатора, наверное, ничем (ну, кроме наглядности и очевидности синтаксиса, подсветки, качества ошибок, расширяемости и т.п.)
Re[13]: Полухин - что там с С++26
От: B0FEE664  
Дата: 27.01.26 10:53
Оценка:
Здравствуйте, Went, Вы писали:

BFE>>Короче, можете объяснить: где вы предполагаете возможность оптимизации?

W>Выражение $"Get {count} of {fruit}.".
W>По отношению к конкатенации ("Get " + std::to_string(count) + " of " + fruit + ".") — нет необходимости многократно перевыделять буферы и копировать.

Ну ка же нет?
результат преобразования {count} в строку может иметь разную длину:
Get 1 of apple.
Get 22 of apple.
Значит копирование строки " of " в заранее выделенный буфер всё равно придётся делать.
{fruit} — строка переменной длины, значит заранее под неё заказать буфер не получится. Следовательно, так или иначе будет копирование строк "Get 1 of " и "apple" в некий третий буфер, который динамически придётся выделять. Да в этом третьем буфере можно заранее учесть завершающую точку и зарезервировать под неё место, но такого рода оптимизации выглядят сомнительно, особенно учитывая, что std::string хорошо оптимизированы для коротких строк и заранее выделяют память под возможное увеличение, ЕМНИП.

Вот пример из исходников:
  template<typename _CharT, typename _Traits, typename _Alloc>
    _GLIBCXX20_CONSTEXPR
    inline basic_string<_CharT, _Traits, _Alloc>
    operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
          basic_string<_CharT, _Traits, _Alloc>&& __rhs)
    {
#if _GLIBCXX_USE_CXX11_ABI
      using _Alloc_traits = allocator_traits<_Alloc>;
      bool __use_rhs = false;
      if _GLIBCXX17_CONSTEXPR (typename _Alloc_traits::is_always_equal{})
    __use_rhs = true;
      else if (__lhs.get_allocator() == __rhs.get_allocator())
    __use_rhs = true;
      if (__use_rhs)
#endif
    {
      const auto __size = __lhs.size() + __rhs.size();
      if (__size > __lhs.capacity() && __size <= __rhs.capacity())
        return std::move(__rhs.insert(0, __lhs));
    }
      return std::move(__lhs.append(__rhs));
    }

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

Наверное где-то можно выиграть 1%-2%, но у меня большие сомнения что это имеет смысл.
И каждый день — без права на ошибку...
Re[14]: Полухин - что там с С++26
От: Went  
Дата: 29.01.26 17:58
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, Went, Вы писали:


BFE>>>Короче, можете объяснить: где вы предполагаете возможность оптимизации?

W>>Выражение $"Get {count} of {fruit}.".
W>>По отношению к конкатенации ("Get " + std::to_string(count) + " of " + fruit + ".") — нет необходимости многократно перевыделять буферы и копировать.

BFE>Ну ка же нет?

BFE>результат преобразования {count} в строку может иметь разную длину:
BFE>Get 1 of apple.
BFE>Get 22 of apple.
BFE>Значит копирование строки " of " в заранее выделенный буфер всё равно придётся делать.
BFE>{fruit} — строка переменной длины, значит заранее под неё заказать буфер не получится. Следовательно, так или иначе будет копирование строк "Get 1 of " и "apple" в некий третий буфер, который динамически придётся выделять. Да в этом третьем буфере можно заранее учесть завершающую точку и зарезервировать под неё место, но такого рода оптимизации выглядят сомнительно, особенно учитывая, что std::string хорошо оптимизированы для коротких строк и заранее выделяют память под возможное увеличение, ЕМНИП.

Я так понимаю. Интерполяция:
1. Приводим count к строке (1 выделение).
2. Суммируем длину строки count, длину строки fruit и длину строки подстановки.
3. Выделяем строку нужного размера (2 выделение).
4. Копируем в неё "Get ", строку count, " of ", строку fruit, "." (15 копирований).
Строго говоря, у нас 2 выделения и 15 копирований.
Теперь сложение.
1. Приводим count к строке (1 выделение).
2. Выделяем строку под "Get " и строку count. Копируем туда (2 выделения и 5 копирований).
3. Выделяем строку под "Get 1 of ", и копируем туда "Get 1" и " of " (уже 3 выделения и 5 + 5 + 4 = 14 копирований)
4. Аналогично для fruit (уже 4 выделения и 14 + 14 + 5 = 33 копирования)
5. Аналогично для "." (уже 5 выделений и 33 + 33 + 1 = 67 копирований).
То есть, у нас 5 выделений и 67 знаков скопировать.
Мог где-то ошибиться, но суть, я думаю, ясна. Если строка с оптимизацией для малых строк, выделений можно избежать, но разница в количестве копирований останется. Однако в реале, интерполяция на очень коротких строках используется редко, так что выделения будут. Кстати, я опустил запись терминального нуля. А с ним копирований будет еще больше (ведь программа не знает, что это промежуточный вариант и ноль можно не писать).
Если я где-то ошибаюсь, подскажите где именно.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.