Template specialisations of free functions are always a bad idea - they don't play nicely with ADL. So I would not recommend convertstd::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 convertstd::string(joiner const& j) {... }
template<> std::wstring convertstd::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
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 convertstd::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