$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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