|
Boost : |
Subject: Re: [boost] Variadic append for std::string
From: Richard Hodges (hodges.r_at_[hidden])
Date: 2017-01-18 11:30:26
I agree re naming. concat() or concatenate() seems a better fit.
I also share your unease re formatting. I have of course shoehorned the
ostream formatters in here without thinking it through deeply (there is
also the issue of the separator getting formatted, so any sequence of
formatters must be executed *after* the separator has been applied, and
formatters really ought to restore previous state.
I think it's reasonable to develop a series of lightweight function object
factories that provide trivial formatting objects in the same way that
std::quoted does for std::ostream.
In that case, it is perfectly reasonable to do away with the entire
atrocious ostream performance bottleneck altogether (perhaps there are
questions though, about formatting options and locales?).
Totally agree with returning a string factory. That makes perfect sense.
onto(x) could return the correct kind of wrapper, depending on the argument
type of x. So it could cope with x being for example, std::string&,
std::string const&, std::string&& or std::ostream&.
As an observation, expressing the join as an iterator pair lends itself to
being implemented in terms of std::copy(first, last,
formatting_iterator<...>).
I think this is good for containers, but for a series of disjoint types, or
for joining words (as opposed to letters), you'd still need some templatery.
boost::range springs to mind as a reasonable helper for expressing to
concat (or join) that you want to treat each element of a container.
On 18 January 2017 at 16:11, Christof Donat <cd_at_[hidden]> wrote:
> Hi,
>
> Am 18.01.2017 10:59, schrieb Richard Hodges:
>
>> int main()
>> {
>> auto s= std::string("foo");
>>
>> s = join("Hello ", ", World.", " The hex for ", 58, " is ", std::hex,
>> 58);
>> std::cout << s << std::endl;
>>
>> s = join(separator(" : "), "a", "b", std::hex, 200 ,
>> std::quoted("banana"));
>> std::cout << s << std::endl;
>>
>> join(onto(s), separator(", "), "funky", "chicken");
>> join(onto(s), "=====");
>> std::cout << s << std::endl;
>> }
>>
>
> I do like the idea, but not the naming. With a function name "join" I'd
> expect to be able to pass an iterator range and have all its element
> concatenated into a string with a defined separator like this:
>
> auto my_number = std::vector<int>{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
> std::cout << join(std::begin(my_number), std::end(my_number), ", ") <<
> std::endl;
>
> expected output:
>
> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
>
> maybe the name cat(), or concatenate() would fit better here.
>
> Also I am not 100% happy with is the reuse of iostream manipulators. They
> already don't have a distinct range of effect in iostream library. Another
> issue is, that the way, they work, is pretty complicated to be reused in a
> high performance implementation.
>
> How about an API like this:
>
> s = concat("Hello ", ", World.", " The hex for ", 58, " is ",
> concat_lib::hex(58));
> s = concat(separator(" : "), "a", "b", concat_lib::hex(100),
> std::quoted("banana"));
>
> concat(onto(s), separator(", "), "funky", "chicken"); // will return a
> reference to s I guess
> concat(onto(s), "=====");
>
> This would go well with what I'd expect with the function name join():
>
> s = join(std::begin(my_number), std::end(my_number));
> // -> "12345678910"
> s = join(separator(", "), std::begin(my_number), std::end(my_number));
> // -> "1, 2, 3, 4, 5, 6, 7, 8, 9, 10"
> join(onto(s), separator(" - "), std::begin(my_number),
> std::end(my_number));
> // -> "1, 2, 3, 4, 5, 6, 7, 8, 9, 101 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10"
>
> Now, when we put it like that, there is no way, to let the functions
> "steal" work from each other. If you take this e.g.:
>
> concat(on(s), join(separator(", "), std::begin(my_number),
> std::end(my_number)), " ",
> join(separator(" - "), std::begin(my_number),
> std::end(my_number)));
>
> This will first execute the two join() calls that return strings, which
> are then passed to concat(). Instead join() and concat() could return
> objects, that can be converted to std::string. Then concat() can make the
> result of join() render its output into a common buffer.
>
> auto s = concat(join(separator(", "), std::begin(my_number),
> std::end(my_number)), " ",
> join(separator(" - "), std::begin(my_number),
> std::end(my_number))).str();
>
> Christof
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman
> /listinfo.cgi/boost
>
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk