Boost logo

Boost :

Subject: Re: [boost] Variadic append for std::string
From: Roberto Hinz (robhz786_at_[hidden])
Date: 2017-01-11 14:03:55

On Wed, Jan 11, 2017 at 3:40 PM, Roberto Hinz <robhz786_at_[hidden]> wrote:

> Hi,
> I've been working in a format library that contains a function template
> called appendf that can do this:
> std::string str("blabla");
> boost::stringify::appendf(str) () (" AAA ", 25, " BBB ", {255, "x"});
> assert(str == "blabla AAA 25 BBB ff"); // ( 255 formated in
> hexadecimal )
> This library - I call it Boost.Stringify - is in very early stage of
> development and I though it would be to premature to mention it now. But
> given the repercussion in this thread so far, I changed my mind. So I will
> soon publish it in github and I will start to write a brief documentation
> so that I can soon present here to gauge interest.
> On Wed, Jan 11, 2017 at 2:45 PM, Christof Donat <cd_at_[hidden]> wrote:
>> Hi,
>> Am 11.01.2017 16:03, schrieb Olaf van der Spek:
>>> On Wed, Jan 11, 2017 at 10:02 AM, Christof Donat <cd_at_[hidden]> wrote:
>>>> The significantly better alternative is std::ostringstream. I think our
>>>> debate showed very nicely, that all the options, we have come up with to
>>>> simplify the concatenation of strings are significantly inferior in
>>>> total,
>>>> though we could find examples, where they slightly improve readability.
>>> Interface is important, as is performance.. and performence of
>>> ostringstream sucks..
>> Well, but obviously up to now we didn't manage to come up with a
>> solution, that has a similar simple, maybe even better interface and allows
>> for faster implementations.
>> I'll try again:
>> Basically the Idea of that kind of interface should work as well for a
>> high performance solution. Let's start with this syntax:
>> auto myString = (cat() + "Hello"s + " "s + "World! "s + 42).str();
>> "cat" would return an object that collects all the values by reference,
>> and concatenates them in one go in the call to str(). Then when str() runs,
>> the information about the string length can be calculated, or at least
>> estimated correctly and no data needs to be copied unnecessarily. I am
>> sure, you see the structural similarity to the usage of std::ostringstream
>> as well. I just chose to use the operator +, because
>> 1. we don't have stream manipulators here, so we don't want people to
>> think, that we are talking about streams and
>> 2. strings already can be concatenated with operator +. Therefore this is
>> an intuitive and not very surprising interface for string concatenation.
>> People might just think, they can add numbers to strings as well without
>> a "cat"-object. There is some room for confusion, but it is much less, than
>> people thinking, strings are a kind of streams. Maybe "cat" is not the best
>> name for this function template, it should express, that here the
>> concatenation includes conversions.
>> We also need an extensible way to define these conversions, because we
>> also will want to add e.g. complex<myBigRelativeType, myBigRelativeType> to
>> a string. We also will want to define the format, because sometimes, we'll
>> want to concat a number in decimal representation, sometimes in
>> hexadecimal, octal, etc. I think, these conversion functions should write
>> to a string view. e.g.:
>> template <> // the default conversion for this type
>> void boost::cat::convert<complex<...>>(std::string_view& output,
>> size_t max_length,
>> const complex<...>& data);
>> We could use parameters to cat to define conversion functions.
>> auto myString = (cat(hex<int>) + 42).str();
>> I am not sure now, if that syntax is so great to define the conversion
>> functions. We'll have to discuss.
>> Of course there should be an optimized default conversion function for
>> cat-objects as well:
>> auto myString = (cat() + "Hello"s + " "s + "World! "s + 42 +
>> (cat(hex<int>) + " "s + 42)).str();
>> Here the outer cat-object would "steal" the values from the inner
>> cat-object and use its conversion functions directly with a view on the big
>> result string.
>> I understand, that the syntax is not 100% what you try to achieve, but I
>> still think, that conversion to string should not be directly done on a
>> string object. This specific object to do concatenation and conversion
>> actually is the key to gain the maximum possible performance, because it
>> can delay the actual concatenation and conversion to a point, where all
>> necessary information is available.
>> Christof
Sorry for top posing in the previous message. It wasn't intentional
Anyway, you can take a look at the source:

Although there is no documentation, the unit tests and performance test
provides some usage examples.

I think it solves this variadic string append perfectly. However it will
take time to get ready.
As I said, perhaps is premature to gauge interest. Still, any interest ?

This is a c++14 format library, that:

- has good performance
- allows the user to extend input types and output types. And when adding
new input types, he can create formating options specifically this new
input type.
- is highly customizable. The user will able to customize, for instance
    - how is the width calculated. It can be simple the length of the
string, or it be the count of unicode code points. Or it can be even more
    - the numeric digits. For instance, to use arabic numbers.
- support all character types.
- its UTF friendly. For instance, while in std::ostream and others the fill
must be a single char, in Boost.Stringify, it is a char32_t. If you a
writing to char*, it is converted into utf-8 by default, but you can
customize that.
- currently can write to std::basic_string, char*. But it support also
FILE* and std::basic_streambuf
- is not locale sensitive. This is not necessarily aways an advantage. But
it would be nice to have one format that is totally not locale sensitive,
and thus ensure that it will aways write exactly the user expect.

Note: I did not test it in Visual Studio. ( gcc and clang only )

Boost list run by bdawes at, gregod at, cpdaniel at, john at