25.4. Concatenation Seeding
Since the + operator is left-to-right associative, the compiler takes its cue from the left-hand argument prior to looking at the right-hand argument. We can take advantage of this to lead it down the path we want it to follow.
In the same namespace as fast_string_concatenator<> is defined another class fsc_seed:
class fsc_seed
{};
We saw references to this in the constructor of the Data nested class and the DataType enum. This class extends the nonintrusive nature of the technique by allowing us to seed a concatenation sequence involving any string type to use fast concatenation:
String s = fsc_seed() + s1 + " " + s2 + " " + s3;
In this case, all we need to make it work is define a single operator +() overload:
fast_string_concatenator<String>
operator +(fsc_seed const &lhs, String const &rhs)
{
return fast_concat_t(lhs, rhs);
}
and the compiler does the rest. The result of the first concatenation is fast_string_concatenator<String>, so the next operator is deduced (via Koenig lookup) to be one of the standard ones in the concatenator's namespace. Naturally, such a thing is a little ugly, but it's better than messing around in the headers of third-party libraries, and it's a solution where otherwise none is available. It also allows you to explicitly use fast concatenation in some parts of your code and not others. It's analogous to operator new(nothrow) (C++-98: 18.4).
Although it hardly counts as a disadvantage, when writing templates you must follow the constraint that the first element in the sequence after the seed is of string class type, rather than a character or a C-style string, since there would be no way to deduce the string type from the character type in the corresponding operator +():
template< . . . >
fast_string_concatenator<S, C, T>
operator +(fsc_seed const &lhs, C const *rhs) // What is S??
{
return fast_string_concatenator<S, C, T>(lhs, rhs);
}
The use of seeding does very little damage to the performance characteristics of fast concatenation.
 |