
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: namespace boost { // the concept template<class To> T convert(joiner const& j); // some specialisations template<> std::string convert<std::string>(joiner const& j) {... } template<> std::wstring convert<std::wstring>(joiner const& j) {... } }; then in user code: template<class T> void do_something(boost::joiner const& j) { using boost::convert; auto v = something(convert<T>(j)); something_else(v); } now someone wishes to provide their own converter, not in the boost namespace: namespace user { struct UserRepresentation; // this is not allowed. There is not already a general template called user::convert<>. It's called boost::convert<> template<> UserRepresentation convert<UserRepresentation>(boost::joiner const& j) { ... } } As mentioned in the comments, this is not allowed. So the user is not forced to specialise the boost namespace. This is not the boost way (see boost::hash), and for good reason. Namespaces are for separation. This forces crowding of the boost namespace. Also, specialising templates in foreign namespaces is a source of user confusion. Google mentioned this in their proposal to make std::hash behave more like boost::hash (std::hash being an example of the standards committee turning a fantastic tool into an incomplete shambles, because they left out the bits that make it work well). If you want a template convert function (and I don't, but I can imagine that some might), then the model to follow would be that of boost::hash<> This uses a function object (boost::hash) which then calls out through a namespace collector and finally to the ADL hash_value function. In our case it would want to call out to a function like convert(boost::tag<T>, boost::joiner const& j) -> T. The general form would be: namespace boost { template<class T> struct join_converter { decltype(auto) operator()(tag<T>, joiner const& j) const { using boost::convert } }; } The signature of the general converter would then be auto convert(boost::tag<T>, joiner const& j) -> T and the user's non-template overload would be: namespace user { auto convert(boost::tag<UserRepresentation>, boost::joiner const& j) -> UserRepresentation; } boost would never define a convert function. Conversions for std::string, std::wstring etc would be specialisations of boost::join_converter. This allows ADL to find non-template converters in namespaces associated with the thing that they are converting to. The generic user calling function would then look more like this: template<class T> void do_something(boost::joiner const& j) { auto convert = boost::converter<T>(); auto v = convert(something(j)); something_else(v); } I'm afraid that this "class template which calls free function" dance is necessary to allow calls to ADL free functions to search beyond the boost namespace. Again, see boost::hash for the gory details. On 26 January 2017 at 14:27, Christof Donat <cd@okunah.de> wrote:
Hi,
Am 26.01.2017 10:47, schrieb Richard Hodges:
I don't see any particular reason why you can't provide all of them,
though (even the implicit conversion), as different things are going to feel more natural to different people, particularly in different contexts.
There's a problem with implicit conversion.
imagine the overloads function:
void foo(std::string const& s);
[...]
foo(join(...));
[...]
void foo(std::string_view s); void foo(const char* s);
Now the above code will not compile, because there are 3 ambiguous overloads.
But that is only an issue for users, who have relied on the implicit conversion upfront. You can always use an implicit conversion explicitly as well, of course, and implicit conversion will be just one of multiple options, if we add it.
The moral of the story is that if we are going to provide conversion
operators, they need to be explicit anyway.
Up to now, you haven't made a point here. Just those users, who decide to rely on implicit conversion, instead of one of the explicit variants, have to cope with the downsides of implicit conversion. Others don't. I think that fits well with "don't pay for what you don't use".
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.
Christof
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman /listinfo.cgi/boost