I've needed recently to convert from chrono::time_point to posix_time::ptime and from chrono::duration to posix_time::time_duration.

This kind of conversions are needed quite often when you use code from two different libraries that have implemented the same concept using of course different representations and have 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 conversions of pairs if the related types are C++ convertible:template <typename T1, typename T2> struct pair { ... template<class U, class V> //requires Constructible// && Constructible std::pair(const pair<U, V>& p); template<class U , class V> //requires HasAssign // && HasAssign std::pair& operator=(const std::pair<U , V>& p); ... };

But as the types

Well we can again define a specific function `Target`

and `Source`

are not C++ convertible other than using 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, the `ConvertToPairOfTarget`

should be generictemplate <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 astemplate <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 followsTarget convert_to(Source& v) { return ConvertToTarget(v); }

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> >)`

do not compiles 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 some kind of conversion, using a constructor or a conversion operator. Do we need to make specialization for these conversion? The answer is no. We need just to define the default implementation of convert_to function to just return the explicit conversion.

template < typename Target, typename Source> Target convert_to(const Source& from) { return Target(from); }

Classes or algorithms relying on a conversion by copy-construction or by the conversion operator can be made more generic by relaying in a function that explicitly states this conversion. Thus, instead of requiring

`Target(from)`

requiresconvert_to<Target>(from)

So one of the advantages of using this common functions is uniformity. The other is that now we are able to find all the explicit conversions to one type, as we can do with explicit casts.

**C++ Evolution?**C++0x has added explicit conversion operators, but they must always be defined in the Source class. The same applies to the assignment operator, it must be defined on the Target class.

What it will interesting is to be able to add constructors and assignments operators to the class std::pair, so we can say that two pairs are convertible if the parameters are explicitly convertible using a convert_to function

template<class U , class V> //requires HasConvertTo// && HasConvertTo std::pair& operator=(const std::pair<U , V>& p) { return std::make_pair( convert_to<T1>(p.first), convert_to<T2>(p.second)); }

But this is not currently possible, we can not add operations to a class.

Another possibility could be to make an evolution to the C++ standard, so the convertible concept takes care of extrinsic conversions. We could be able to implicitly or explicitly add extrinsic conversion operators between unrelated types.

template < typename To, typename From > operator To(const From& val);

For example we could specialize the conversion from chrono::time_point to posix_time::ptime as follows

template < class Clock, class Duration> operator boost::posix_time::ptime( const boost::chrono::time_point<Clock, Duration>& from) { using namespace boost; typedef chrono::time_point<Clock, Duration> time_point_t; typedef chrono::nanoseconds duration_t; typedef duration_t::rep rep_t; rep_t d = chrono::duration_cast<duration_t>( from.time_since_epoch()).count(); rep_t sec = d/1000000000; rep_t nsec = d%1000000000; return posix_time::from_time_t(0)+ posix_time::seconds(static_cast<long>(sec))+ posix_time::nanoseconds(nsec); }

```
```

## No comments:

## Post a Comment