Здравствуйте, maks1180, Вы писали:
M>Нужно реализовать быстрый sprintf, соотвественно:
проблема sprintf, что он создаёт строку как промежуточное звено между источником и получателем.
Можно попробовать сделать ленивую строку, которая будет хранить необходимую информацию для форматирования и только при итерировании по ней будет проводить необходимые вычисления. Примерный draft:
#include <variant>
#include <optional>
// методы begin и end надо реализовать и реализацию Iter в зависимости от функции next()
struct CharIterable {
struct Iter{};
std::optional<Iter> next( return std::nullopt; ) const;
};
struct IntValue: CharIterable
{
private: int val = 0;
};
struct StrValue: CharIterable
{
private: const char* val = "";
};
using Value = std::variant<IntValue, StrValue>;
template<int N>
struct LazyFormatter: CharIterable
{
private: const char* format;
private: Value values[N];
};
template<>
struct LazyFormatter<0>: CharIterable
{
public: LazyFormatter(const char* fromat){};
private: const char* format;
};
template<int N>
auto operator+(const LazyFormatter<N>& f, Value v) {
return LazyFormatter<N + 1>{};
}
int main() {
const auto to_log = LazyFormatter<0>{"{}{}"} + IntValue{} + StrValue{};
return 0;
}
new/delete нет. Всё на стеке. Я не уверен, что овчинка стоит выделки. Надо мерять. Но оно точно понадёжнее, чем играться с регистрами.
Намного проще решение — предположить что int при форматировании никогда не превысит размера 11 н-р. double — 15 и т д. И делать конкатенацию сразу
stack_string{"int value: "} + stack_string::fromInt(42) + stack_string{ ", some string value: " } + stack_string::fromStaticStr("text");
тоже динамической аллокации нет. Но тут мы имеем некоторый перерасход за счёт наших допущений на максимальную длину. Ну и не constexpr строку не засунуть