Boost logo

Boost :

Subject: Re: [boost] Variadic append for std::string
From: Christof Donat (cd_at_[hidden])
Date: 2017-01-24 04:30:49


Am 24.01.2017 00:14, schrieb Gavin Lambert:
> On 24/01/2017 07:26, Olaf van der Spek wrote:
>>> 1. scope for formatting tags:
>>> concat(format::hex<int>, 42, " is hex for ", concat(42)).str();
>>> Here the inner concat will convert the 42 to its decimal
>>> representation,
>>> while the outer one converts the first 42 to its hex representation.
>> Wouldn't concat(hex(42), " is hex for", 42) make more sense?
> +1. If you like persistent formatting states (and all the unexpected
> fun they cause when you forget to cancel them), use iostreams instead.

My proposal does not have anything similar to iostream manipulators. The
conversion tags always extend to the whole concat parameter list, but
not to enclosed calls to concat. There is no change in behavior that
depends on the position of the conversion tag in the parameter list.
Actually I think, we should be able to put all the conversion tags at
the beginning of the parameter list.

>>> 3. results from concat() in a boost::range that is passed to join():
>>> join(separator("\n"),
>>> my_files | transformed([](const std::filesystem::path& f) ->
>>> auto {
>>> return concat(f.filename, ": ",
>>> std::filesystem::file_size(f));
>>> })).str();
> Maybe I missed something, but what was the intended distinction
> between concat() and join()?

The distinction is the same as in many other languages: join() works on
sequences, while concat() works on its parameters.

> To me, as vocabulary words, concat() implies "concatenate without
> separator" and join() implies "concatenate with separator"; as such it
> seems unnecessary to explicitly decorate the separator here since it's
> a required parameter.

I see. The approach, we had here up to now was, to define formatting
specifics as tag parameters at the beginning of the parameter list. If
you give no separator to join() it just puts all the representations of
the sequences objects in a row without any space in between. In Python
the equivalent would be to join on the empty string:

Then, of course it is reasonable to use the same tags for join(), and
concat(), and actually as well for format(), but there separator() is

I agree, that your definition is mostly consistent with what I found for
other languages as well, but most of them also only use join() on
sequences and concat() or equivalents on parameter lists. In languages,
where join() is used on parameter lists as well, like Java or Perl,
there is no other concatenation function. I guess, concat() usually has
no separator in most languages, because you can easily put it in as
additional parameters. With my proposal, it just comes for free.

> (Both should accept either variadics or ranges, if that's not too
> complicated to arrange, though it's likely for join() to be used more
> often on ranges; concat() might be more evenly split, though probably
> leaning toward variadics.)

That part is not consistent with what I found from other languages. Just
Perl and Java (from the list of languages I checked), use join() for
both usecases, but they don't have anything else, that is like concat()
then. All the other distinguish between concatenating a few parameters,
and joining a sequence.

>>>> If "concat" is the outer layer anyway, I would return a std::string
>>>> directly for convenience. It is easy to forget the trailing .str()
>>>> and
>>>> it does not look elegant.
>>> Of course better proposals are welcome :-) Would you prefer the
>>> implicit
>>> conversion? If so, why?
>> Implicit is problematic with auto..
> While that's true, I think the flexibility of returning a factory from
> concat() is more useful than the discomfort of either remembering the
> str() or using std::string explicitly as the type instead of auto (or
> using auto combined with explicit std::string construction).

I agree. Would you prefer str(), or implicit conversion?


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