Boost logo

Boost :

Subject: Re: [boost] [conversion] Motivation for two NEW genericconver_to and assign_to functions
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2009-10-26 17:44:12


Hi Robert,
----- Original Message -----
From: "Stewart, Robert" <Robert.Stewart_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Monday, October 26, 2009 9:46 PM
Subject: Re: [boost] [conversion] Motivation for two NEW genericconver_to and assign_to functions

>
> vicente.botet wrote:
>>
>> I have modified the convert_to implementation with your
>> suggestions (see below) and now we can do:
>>
>> B b;
>>
>> A a1 (convert_to(b, type_tag<A>() ));
>>
>> The user can add overloading on the namespace of the class
>> From, or specialize the boost::conversion::convert_to function.
>>
>> I have defined the tag with a defaulted parameter value
>> type_tag<Target> tag=type_tag<Target>(), so we can also do
>>
>> A a1 (convert_to<A>(b));
>
> This expansion of use cases will make the function more confusing and, I think, increase the opportunities to create ambiguities.
>
> I fail to understand why
>
> convert_to(b, type_tag<A>())
>
> is acceptable and
>
> convert_to<A>(b)
>
> is not in any circumstance.
>
> The former is more verbose and both require the template parameter A.
>
> I understand that the former uses ADL to find the appropriate overload of a normal function, whereas the latter uses a function template specialization to define the function. I also understand that the former can appear in B's or A's namespace (or both!), whereas the latter must be in the boost::conversion namespace. What I don't understand is why the former is preferable to the latter, or why both are deemed necessary.

Well, don't exactlly. The former uses ADL, but it seems to me quite extrange that the developer will add the overload in the Target namespace which has only a type_tag<Target> parameter. But of course this ambiguity is always possible.

    template <typename Target, typename Source>
    Target convert_to(Source const& from, type_tag<Target> tag=type_tag<Target>()) {
        return ::boost_conversion_impl::convert_to_impl<Target>(from);
    }

The second case works because tag is a defaulted parameter. So there is no template specialization on the second case.

convert_to<A>(b);

is equivalent to

convert_to(b, type_tag<A>());

Not a different think.
 
The user need template specialization only if it can not add new function to the name space, as it is the case for the namespace std, isn't it? In this case we need to partialy specialize the nboost::conversion::convert_to function.

> For the latter version, the author of A, aware of B, could provide convert_to<A,B>() and the author of B could provide a generic version that might work for A, thus creating an ambiguity. Likewise, for the former variant, an overload could be declared in both A's and B's namespace. Thus, both approaches can lead to ambiguities, making neither better than the other. Indeed, supporting both would likely lead to even more chances for ambiguity.

As I said there is no need to template specialization, if we can add an overload found by ADL.

The main idea of convert_to is for unrelated libraries, neither of them will provide any conversion. But you are right, a developer would retrieve two definition of the same function done by two parties. Don't we have the same problem with a class A that doesnt provides a swap function, if two parties could specialize it and a third user could retrieve both definitions having an ambiguity?

>> I have added still an overloading to simplify some uses as
>>
>> a = convert_to(b, a);
>>
>> The Target parameter is not used other than to retrieve the type.
>>
>> template <typename Target, typename Source>
>> Target convert_to(Source const& from, Target const&);
>
> That form doesn't make sense to me. If you already have an object of type Target to pass as the second argument, why not just use the following signature?
>
> template <typename Target, typename Source>
> void
> convert_to(Target & _dest, Source const & _from);

You are righ. This was not a good idea.
 
> That keeps the Target and Source values in the same order as the other variations (Target is on the lhs of the value-returning variations) and avoids the duplication of return value and argument.
>
> That function might be easier to use in some cases were it declared like this:
>
> template <typename Target, typename Source>
> Target &
> convert_to(Target & _dest, Source const & _from);
>
> (It would simply return _dest after assigning the converted value to _dest.)

Boost.Conversion provides already a function assign_to with exactly this prototype.

template <typename Target, typename Source>
   Target& assign_to(Target & _dest, Source const & _from);

Note the difference, convert_to don't return by reference. I have prefered to name these two function differently. Is the following a valid overloading?

    template <typename Target, typename Source>
    Target convert_to(Source const& from, type_tag<Target> tag=type_tag<Target>());

    template <typename Target, typename Source>
   Target& convert_to(Target & to, Source const & from);

Thank you very much for your pertinent comment. I will add on the documentation this possible ambiguity, even if I have no mean to avoid it.

Vicente


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk