Boost logo

Boost :

Subject: Re: [boost] Variadic append for std::string
From: Richard Hodges (hodges.r_at_[hidden])
Date: 2017-01-26 13:44:53


> Of course I have no issue, when .to() and .append_to() resort to a free
function, that can be overloaded using ADL, like you had proposed:

If member functions are resolving to ADL free functions via a function
object, I'm fully ok with that.

> Is there a problem for ADL, when stringify_to() is a template on the
string factory?

Yes unfortunately. The template has the name `boost::stringify_to`
regardless of the types. But if you go via a template functor object that
uses ADL to find the free function, then the free function does not have to
be a template function, and ADL will work as expected. In order to make the
free function non-template you need to pass some trivial identifier from
the function's namespace as an argument. So you'll need a tag type.

so:

namespace boost {

  template<class Tag>
  string_factory {
    using type = typename Tag::type;
    type operator()(joiner const& j) const {
      return stringify_to(Tag(), j);
    }
  };

}

which gets syntactically nasty.

which is why we have names like to_string(), hash_code() and so on... :)

On 26 January 2017 at 18:08, Christof Donat <cd_at_[hidden]> wrote:

> Hi,
>
> This is not the boost way (see boost::hash), and for good reason.
>>
>
> Well, the extension points to boost::spirit work by specializing e.g.
> is_contaner<>, or is_string<>. See http://www.boost.org/doc/libs/
> 1_61_0/libs/spirit/doc/html/spirit/advanced/customize/is_container.html
> That is the same for traits in the standard library, so it actually is a
> common pattern. I understand, that e.g. std::swap does it the way, you
> propose.
>
> Am 26.01.2017 15:04, schrieb Richard Hodges:
>
>> Template specialisations of free functions are always a bad idea - they
>>>> don't play nicely with ADL. So I would not recommend
>>>> convert<std::string>(join(...)) etc.
>>>>
>>>
>> Please elaborate more on that. I can't see it.
>>>
>>
>> imagine:
>> [...]
>> now someone wishes to provide their own converter, not in the boost
>> namespace:
>>
>
> Actually I prefer to define a concept for targets of something like
> convert(). The generic convert() then just works with that concept. Then
> only users, who want to write to something, that does not fulfill the
> concept. We might also provide a few specializations like char*, that do
> not obey to the defined concept.
>
> Actually I'd avoid the word "convert" here, because I'd use convert() for
> a function, that returns a string factory to convert a single value. Other
> than concat(), the "string factory" returned by convert() will be able to
> convert in different ways, similar to boost::lexical_cast<>. Currently my
> favorite API looks like this:
>
> auto i = convert("42"s).to<int>();
> // i = 42
> // convert can convert from string to objects as well, like lexical_cast
>
> auto s = convert(i).to<std::string>();
> // s == "42"
> hex(i).to(s);
> // s == "2A"
> convert(23).to(s);
> // s = "23"
> // convert(), hex(), and similar functions return string factories.
>
> append(concat(" - the hex representation of ", i, " is ", hex(i))).to(s);
> // s = "23 - the hex representation of 42 is 2A"
> concat("the hex representation of ", i, " is ", hex(i)).to(s);
> // s = "the hex representation of 42 is 2A"
> append(" Yeah!").to(s);
> // s = "the hex representation of 42 is 2A Yeah!"
>
> auto my_numbers = std::vector<int>{11, 12, 13, 14, 15};
> join(separator(", "), my_numbers).to(s);
> // s = "11, 12, 13, 14, 15"
> join(separator(", "), std::begin(my_numbers), std::end(my_numbers)).to(s);
> // s = "11, 12, 13, 14, 15"
> join(separator(", "), my_numbers | hex).to(s);
> // s = "B, C, D, E, F"
> // join() works with iterator pairs, ranges and range expressions
>
> append(format(" - the hex representation of {2} is {1}", hex(i), i)).to(s);
> // s = "B, C, D, E, F - the hex representation of 42 is 2A"
> format("the hex representation of {2} is {1}", hex(i), i).to(s);
> // s = "the hex representation of 42 is 2A"
>
> auto v = hex(i).to<std::vector<char>>();
> // v == {'2', 'A'}
> append(convert(i)).to(v);
> // v == {'2', 'A', '4', '2'}
>
> It almost reads like English cluttered with some weird punctuation. Of
> course I have no issue, when .to() and .append_to() resort to a free
> function, that can be overloaded using ADL, like you had proposed:
>
> class string_factory {
> public:
> // ...
>
> template <typename TargetT>
> auto to(TargetT& t) -> TargetT& {
> return stringify_to(*this, t);
> };
> template <typename TargetT>
> auto to() -> TargetT {
> TargetT r;
> to(r);
> return r;
> };
> };
>
> Is there a problem for ADL, when stringify_to() is a template on the
> string factory?
>
> template <typename StringFactory>
> myTargetType& stringify_to(StringFactory& f, myTargetType& t) {
> // ...
> }
>
> Then we can avoid virtual function calls in the string factory.
>
>
> 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