Boost logo

Boost :

Subject: Re: [boost] Variadic append for std::string
From: Christof Donat (cd_at_[hidden])
Date: 2017-01-26 12:08:33


> 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
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

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"
// s == "2A"
// s = "23"
// convert(), hex(), and similar functions return string factories.

append(concat(" - the hex representation of ", i, " is ",
// 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),
// 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),
// 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'}
// 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 {
     // ...

     template <typename TargetT>
     auto to(TargetT& t) -> TargetT& {
         return stringify_to(*this, t);
     template <typename TargetT>
     auto to() -> TargetT {
         TargetT 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.


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