|
Boost : |
Subject: Re: [boost] [review] Conversion review ends today
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2011-08-29 13:08:43
Le 29/08/11 18:07, Jeffrey Lee Hellrung, Jr. a écrit :
> On Mon, Aug 29, 2011 at 7:41 AM, Gordon Woodhull<gordon_at_[hidden]>wrote:
>
> Gordon,
>
> I'm considering writing a review, but it will necessarily be late (sometime
> this week?).
>
> My initial inclination is to vote against acceptance of the library due to
> what I currently perceive to be a lack of "real-world use", since it seems
> like the margin of error for "getting it right" for these extrinsic
> conversion operators is pretty small. However, I intend to review the
> documentation to provide feedback nonetheless.
Jeffrey I don't think your vote could change the review result :(.
Anyway, any comment on the library is welcome.
> Vicente, if you have some real-world use cases that you know of, please
> share.
>
I removed the initial motivation from the documentation (it is a little
bit long). Here it is what I wrote:
"
I've needed recently to convert from `boost::chrono::time_point<Clock,
Duration>` to `boost::posix_time::ptime` and from
`boost::chrono::duration<Rep, Period>` to
`boost::posix_time::time_duration`. These kinds of conversions are
needed quite often when you use code from two different libraries that
have each implemented the same concept using a different representation,
and hard-coded the library interface to its own implementation. Well,
this is a normal situation we can't avoid. Life is life.
Quite often we need to convert unrelated types `Source` and `Target`. As
these classes are unrelated, neither of them offers conversion operators
to the other. Usually we get it by defining a specific function such as
Target ConvertToTarget(Source& v);
In my case I started by defining
template <typename Rep, typename Period>
boost::posix_time::time_duration convert_to_posix_time_time_duration(
const boost::chrono::duration<Rep, Period>& from);
template <typename Clock, typename Duration>
posix_time::ptime convert_to_posix_time_ptime(const
chrono::time_point<Clock, Duration>& from);
Imagine now that you need to convert a `std::pair<Source, Source>` to a
`std::pair<Target, Target>`. The standard defines conversion of two
pairs types if the related types are C++ convertible:
template <typename T1, typename T2>
struct pair {
...
template<class U, class V>
//requires Constructible<T1, const U&> && Constructible<T2,
const V&>
std::pair(const pair<U, V>& p);
template<class U , class V>
//requires HasAssign<T1, const U&> && HasAssign<T2, const V&>
std::pair& operator=(const std::pair<U , V>& p);
...
};
As the types `Target` and `Source` are not C++ convertible other than
using a specific function, we need to use a workaround.
We can again define a specific function
std::pair<Target,Target>
ConvertToPairOfTarget(std::pair<Source,Source>& v) {
return std::make_pair(ConvertToTarget(v.fisrt),
ConvertToTarget(v.second));
}
While the `ConvertToTarget` could be specific, it seems clear to me that
the `ConvertToPairOfTarget` should be generic
template <typename Target1, typename Target2, typename Source1,
typename Source2)
std::pair<Target1,Target2>
ConvertToPair(std::pair<Source1,Source2>& v);
In order to do that we need that the pair template parameters define a
common function, let it call __convert_to,
template <typename Target, typename Source)
Target convert_to(Source& v);
so `ConvertToPair` can be defined as
template <typename Target1, typename Target2, typename Source1,
typename Source2)
std::pair<Target1,Target2>
ConvertToPair(std::pair<Source1,Source2>& v) {
return std::make_pair(convert_to<Target1>(v.fisrt),
convert_to<Target2>(v.second));
}
We need to specialize the __convert_to function for the specific classes
`Source` and `Target`. We can do it as follows
Target convert_to(Source& v) {return ConvertToTarget(v);}
Note that the preceding overloads doesn't really work, as C++ doesn't
use the result type on overload resolution. The library uses a
customization point that takes into account the result type.
In my case I needed
template <typename Rep, typename Period>
boost::posix_time::time_duration convert_to(const
boost::chrono::duration<Rep, Period>& from)
{
return convert_to_posix_time_time_duration(from);
}
template <typename Clock, typename Duration>
boost::posix_time::ptime convert_to(const
boost::chrono::time_point<Clock, Duration>& from)
{
return convert_to_posix_time_ptime(from);
}
So now I can convert
std::pair<chrono::time_point<Clock, Duration>,
boost::chrono::duration<Rep, Period> >
to
std::pair<boost::posix_time::ptime, boost::posix_time::time_duration>
using the `ConvertToPair` function.
What about converting `std::pair<Source,std::pair<Source,Source> >` to
`std::pair<Target,std::pair<Target,Target> >`? The issue now is that
`convert_to(std::make_pair<to, std::make_pair<to,to> >)` does not
compile because the conversion of `std::pair` is named `ConvertToPair`.
So we need to specialize the function __convert_to for pairs.
template <typename T1, typename T2, typename S1, typename S2)
static std::pair<T1,T2> convert_to(std::pair<Source1,Source2>& from) {
{
return std::pair<T1,T2>(convert_to<T1>(from.first),
convert_to<T2>(from.second));
}
There is still a last point. The preceding design works well with
unrelated classes, but what about classes that already define conversion
via a constructor or a conversion operator - do we need to specialize
these conversions? The answer is no. We need to define the default
implementation of the __convert_to function to just return the explicit
conversion.
template < typename Target, typename Source>
Target convert_to(const Source& from)
{
return Target(from);
}
As noted above these overloads don't work, and the library uses a
customization point that takes into account the result type."
Let me know if this is enough real for you.
Best,
Vicente
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk