TGViewer
C++ - Reddit C++ - Reddit @r_cpp · 229 subscribers
Post #24699 11
How to concatenate strings quickly? Expression Templates to the rescue!

In this short post, I want to briefly describe the "Expression Templates" technique I use in the [simstr](https://github.com/orefkov/simstr) library to speed up string concatenation. The main point is that when adding several string operands, temporary intermediate strings are not created, into which characters are sequentially added, which leads to repeated allocation and movement of characters from buffer to buffer. Instead, the length of the final result is calculated only once, space is allocated for it only once, and the characters of the operands are copied directly to the final buffer in their place.

This is achieved using so-called "string expressions".

A string expression is an object of any type that has the following methods:

size_t length() const; // Returns the length of its operand
K* place(K* ptr) const; // Places the characters of the result into the provided buffer, returns the position after them

To check that a type is a string expression, a concept is created

template<typename A>
concept StrExpr = requires(const A& a) {
typename A::symb_type;
{ a.length() } -> std::convertible_to<size_t>;
{ a.place(std::declval<typename A::symb_type*>()) } -> std::same_as<typename A::symb_type*>;
};

Then any string object that wants to be initialized from a string expression will first request its length, then allocate the necessary space, and ask the string expression to be placed in that space.

And then a little template magic. We create a template class `strexprjoin`:

template<StrExpr A, StrExprForType<typename A::symb_type> B>
struct strexprjoin {
using symb_type = typename A::symb_type;
const A& a;
const B& b;
constexpr strexprjoin(const A& a_, const B& b_) : a(a_), b(b_){}
constexpr size_t length() const noexcept {
return a.length() + b.length();
}
constexpr symb_type* place(symb_type* p) const noexcept {
return b.place(a.place(p));
}
};

As you can see, this class itself is a string expression. It stores references to two other string expressions. When its length is requested, it returns the sum of the lengths of the expressions stored in it. When asked to place characters, it first places the characters of the first expression, and then the second.

It remains to make a template addition operator for two string expressions:

template<StrExpr A, StrExprForType<typename A::symb_type> B>
constexpr strexprjoin<A, B> operator+(const A& a, const B& b) {
return {a, b};
}

Now any two objects that satisfy the string expression concept can be added, and the result will be a `strexprjoin` object, storing references to its terms: `e1 + e2 --> ej[e1, e2]`. And since this new object also satisfies the string expression concept, you can also apply addition with the next string expression: `e1 + e2 + e3 --> ej[e1, e2] + e3 --> ej[ej[e1, e2], e3]`. Thus, you can build chains of several operands.

When a string object, during initialization, requests the required length from the final result of addition operations, it will return the sum of the lengths of the operands included in it, and then sequentially place their characters into the resulting buffer.

This technology provides fast concatenation of several strings. But this technique is not limited to this. After all, a string expression can not only copy a string, but also create strings itself.

For example, you can create a string expression that generates N given characters:

template<typename K>
struct expr_pad {
using symb_type = K;
size_t len;
K s;
constexpr expr_pad(size_t len_, K s_) : len(len_), s(s_){}
constexpr size_t length() const noexcept {
return len;
}
constexpr symb_type* place(symb_type* p) const noexcept {
if (len)
std::char_traits<K>::assign(p, len, s);
return p + len;
}
};

And voila,
GitHub GitHub - orefkov/simstr: Yet another C++ strings library implementation Yet another C++ strings library implementation. Contribute to orefkov/simstr development by creating an account on GitHub.
More from @r_cpp
  1. Oct 8, 2026Removed by Reddit Removed by Reddit on account of violating the [content policy. ] https:/…
  2. Oct 8, 2026Is there a way to search across all P and N papers throughout standardization history? It…
  3. Oct 8, 2026CppCast Episode 412 : Safety and Interoperability with Rust and C++ https://cppcast.com/sa…
  4. Oct 8, 2026VeloCache: A high-performance, Redis-compatible in-memory key-value store built from scrat…
  5. Oct 8, 2026Which C++ Hashmap Should You Actually Use? https://martin.ankerl.com/which-hash-map/ https…
  6. Oct 8, 2026Lazy Evaluation - Operators https://breese.github.io/2026/09/04/lazy-operator.html https:/…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →