Boost logo

Boost :

Subject: Re: [boost] Variadic append for std::string
From: Richard Hodges (hodges.r_at_[hidden])
Date: 2017-01-24 07:12:32


>
> The second version I reject regardless, because it uses an overloaded
> operator |.
>

> That is the adaptor API from boost::range and is the same in ranges::v3.
It's not my invention.

I must admit that I share Hans' distaste of the pipe overloads. I find them
harder to read than a sequence of function calls, and to me they are not
immediately expressive.

I agree that explicit is better than implicit.

I also strongly feel that .str() is an error, since it couples the concepts
of strings with joiners, or concatenators. Strings have allocators and
traits. I feel that a free function is more decoupled, and could even go in
a separate header file to reduce complexity.

In summary,

to_string(x) is better than x.str() is better than implicit conversion.

It is my view that this little interface change would make boost::format
more std-like and consistent. It would also make template programming more
convenient, since template expansion works much more nicely with ADL than
with member functions. The ADL free functions act as glue for objects that
lack a .str() member.

e.g:

#include <boost/format.hpp>
#include <iostream>

namespace boost {
    auto to_string(const boost::format& f) -> std::string
    {
        return f.str();
    }
}

int main()
{
    auto s = to_string(boost::format("%1%") % "hello");
    std::cout << s << std::endl;
}

I'll make a suggestion about this in the boost::format forum.

On 24 January 2017 at 12:54, Christof Donat <cd_at_[hidden]> wrote:

> Hi,
>
> Am 24.01.2017 11:52, schrieb Hans Dembinski:
>
>> Would you prefer str(), or implicit conversion?
>>>
>>
>> Please, no implicit conversion. I don't like .str() but it is better
>> than implicit conversion. Implicit conversion is confusing, especially
>> in the context of templates and auto.
>>
>
> I didn't have good reasons, but this is in line with my gut feeling. I
> totally agree.
>
> If format::hex<int> is allowed to be in any position and still affect
>> the whole string, that is not at all intuitive.
>>
>
> My idea was to allow those formatting tags only at the beginning of the
> parameter list. Then separator("sadf") is just another formatting tag.
>
> What happens when you
>> have two conflicting formatting tags in the argument list? Which one
>> wins?
>>
>
> OK, here you made a point. In a specification I'd leave the behavior
> undefined. In an actual implementation I'd have the later ones overwrite
> the previous ones, because I expect that to be easy to implement. We could
> also try and prevent that with meta programming, but I think, that is not
> worth the effort. Leaving it unspecified in the specification, still leaves
> us the option to do that later.
>
> join(hex<int>, separator(" "), my_nums);
>>>
>>> Here all the numbers are converted to their hex representation. With
>>> your approach this would look like:
>>>
>>> join(separator(" "),
>>> my_nums | transform([](int i) -> int {
>>> return hex(i);
>>> }));
>>>
>>> That is much more difficult to understand.
>>>
>>
>> I don't see how that follows. You are free to write an overload for
>> "join" which accepts an unary function as the first argument, which is
>> then applied to all the values in the range. If hex<int> is an unary
>> function, the first version makes even more sense.
>>
>
> I think, that composes less elegantly with boost::range or ranges::v3.
> Maybe we could lean towards their adaptor APIs like this:
>
> join(separator(" "), my_nums | hex<int>()));
>
> Still separator("...") is a bit out of the picture now. Up to mow I
> thought, that it is some kind of formatting information and therefore I
> handled it like other formatting tags. Actually I begin to like the idea of
> formatting functions, that return string factories. That fits very nicely
> with the rest of the API and makes concat(), join() and format() simpler.
>
> A completely different approach, inspired by Python:
>
> separator(" ").join(my_nums | hex<int>());
>
> Then we add free functions like this:
>
> template<typename Sequence
> auto join(const Sequence& seq) {
>
> }
>
> The second version I reject regardless, because it uses an overloaded
>> operator |.
>>
>
> That is the adaptor API from boost::range and is the same in ranges::v3.
> It's not my invention.
>
> 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