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/cu... 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