
Le 29/08/11 18:07, Jeffrey Lee Hellrung, Jr. a écrit :
On Mon, Aug 29, 2011 at 7:41 AM, Gordon Woodhull<gordon@woodhull.com>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