[review] Conversion review ends today

Folks, The review of Vicente's Conversion library ends today. Unfortunately there have only been four reviews, which is hardly enough to provide proper feedback. If you've considered writing a review or if you have any thoughts about the topic, please speak up now. Or if you'd like to submit a late review, just let me know. Thanks, Gordon

On Mon, Aug 29, 2011 at 7:41 AM, Gordon Woodhull <gordon@woodhull.com>wrote:
Folks,
The review of Vicente's Conversion library ends today.
Unfortunately there have only been four reviews, which is hardly enough to provide proper feedback.
If you've considered writing a review or if you have any thoughts about the topic, please speak up now. Or if you'd like to submit a late review, just let me know.
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. Vicente, if you have some real-world use cases that you know of, please share. - Jeff

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

On Mon, Aug 29, 2011 at 10:08 AM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 29/08/11 18:07, Jeffrey Lee Hellrung, Jr. a écrit :
[...]
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.
Your example of converting between boost::chrono objects and boost::posix_time objects is, indeed, a real use case, so thank you. I can imagine other similar use cases, where you want objects from two independent libraries to be interconvertible. But this isn't *quite* what I was looking for. Have you (or do you know someone who has) used the framework provided by Boost.Conversion to utilize conversions in a generic setting (e.g., generic algorithms or data structures)? If not or not so much, are we hoping that such algorithms and data structures will be created in the future? I'm feeling like I'm missing something here regarding the library's utility. I admit I haven't gone though the documentation, but I think I have a general idea of what the library is trying to achieve immediately (provide extrinsic conversions between unrelated types). What about beyond that immediate goal? I, too, had an application that required unrelated types to be interconverted, and generic algorithms and data structures that required these conversions. I initially constructed a generic framework similar to that defined by Boost.Conversion, but ultimately I discarded this framework in favor of the conversions being handled by a function object with signature operator()(const Srce& srce, type_tag< Dest >) -> Dest, since the conversions required additional context than that given by the Srce object. So my experience may be coloring my perceptions. I hope I don't sound too negative :/ - Jeff

Le 30/08/11 20:43, Jeffrey Lee Hellrung, Jr. a écrit :
On Mon, Aug 29, 2011 at 10:08 AM, Vicente J. Botet Escriba< vicente.botet@wanadoo.fr> wrote:
Le 29/08/11 18:07, Jeffrey Lee Hellrung, Jr. a écrit :
[...]
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:
Let me know if this is enough real for you.
Your example of converting between boost::chrono objects and boost::posix_time objects is, indeed, a real use case, so thank you. I can imagine other similar use cases, where you want objects from two independent libraries to be interconvertible. But this isn't *quite* what I was looking for. Have you (or do you know someone who has) used the framework provided by Boost.Conversion to utilize conversions in a generic setting (e.g., generic algorithms or data structures)? If not or not so much, are we hoping that such algorithms and data structures will be created in the future?
I'm feeling like I'm missing something here regarding the library's utility. I admit I haven't gone though the documentation, but I think I have a general idea of what the library is trying to achieve immediately (provide extrinsic conversions between unrelated types). What about beyond that immediate goal? I, too, had an application that required unrelated types to be interconverted, and generic algorithms and data structures that required these conversions.
Maybe you can share theese use cases with us.
I initially constructed a generic framework similar to that defined by Boost.Conversion, but ultimately I discarded this framework in favor of the conversions being handled by a function object with signature operator()(const Srce& srce, type_tag< Dest>) -> Dest, since the conversions required additional context than that given by the Srce object. This seems similar to the Gordon suggestion. While this approach could work on most of the cases, is not able to manage with different conversion for the same couple of Source/Target types but applied to different leaves.
The single way Boost.Conversion could take care of these specific cases and also concept refinement is to wrap the parameter with a specific class. But this could not be enough efficient and quite cumbersome.
So my experience may be coloring my perceptions.
I hope I don't sound too negative :/
Don't worry. I agree with all of you that the library has deep holes and that another design seems to be needed to cover with the generic conversions. I hope that someone else will make a proposal that will cover with. Best, Vicente

Hi Jeff, Vicente, On Aug 30, 2011, at 4:50 PM, Vicente J. Botet Escriba wrote:
Le 30/08/11 20:43, Jeffrey Lee Hellrung, Jr. a écrit :
I, too, had an application that required unrelated types to be interconverted, and generic algorithms and data structures that required these conversions.
Maybe you can share theese use cases with us.
+1
I initially constructed a generic framework similar to that defined by Boost.Conversion, but ultimately I discarded this framework in favor of the conversions being handled by a function object with signature operator()(const Srce& srce, type_tag< Dest>) -> Dest, since the conversions required additional context than that given by the Srce object.
This is the same signature Conversion uses, only it uses function overloading instead of function objects. Jeff, what method did you use to glue together the various function objects into one?
This seems similar to the Gordon suggestion. While this approach could work on most of the cases, is not able to manage with different conversion for the same couple of Source/Target types but applied to different leaves.
The single way Boost.Conversion could take care of these specific cases and also concept refinement is to wrap the parameter with a specific class. But this could not be enough efficient and quite cumbersome.
Vicente, what do you mean by "different leaves"? I wasn't aware that choosing different conversion behaviors was in the scope of the current library/review. Cheers, Gordon

Le 31/08/11 20:55, Gordon Woodhull a écrit :
Hi Jeff, Vicente,
On Aug 30, 2011, at 4:50 PM, Vicente J. Botet Escriba wrote: This seems similar to the Gordon suggestion. While this approach could work on most of the cases, is not able to manage with different conversion for the same couple of Source/Target types but applied to different leaves.
The single way Boost.Conversion could take care of these specific cases and also concept refinement is to wrap the parameter with a specific class. But this could not be enough efficient and quite cumbersome. Vicente, what do you mean by "different leaves"? I wasn't aware that choosing different conversion behaviors was in the scope of the current library/review. What I mean is that if the user wants to convert two leafs (of type int) to strings using different conversions she will need to replace the ints by different types. Boost.Conversion doesn't allows to choose different conversion for the same type, but neither the functor.
Best, Vicente

On Aug 31, 2011, at 3:42 PM, Vicente J. Botet Escriba wrote:
Boost.Conversion doesn't allows to choose different conversion for the same type, but neither the functor.
Got it. I think there are two different use cases here: * want different implementation (coerce vs lexical_cast) - maybe an argument for conversion domains or tags. Wrapping does seem cumbersome. * need to specify parameters (like radix) - not generic, use a specific conversion library.

On Wed, Aug 31, 2011 at 11:55 AM, Gordon Woodhull <gordon@woodhull.com>wrote:
Hi Jeff, Vicente,
Le 30/08/11 20:43, Jeffrey Lee Hellrung, Jr. a écrit :
I, too, had an application that required unrelated types to be interconverted, and generic algorithms and data structures
On Aug 30, 2011, at 4:50 PM, Vicente J. Botet Escriba wrote: that
required these conversions.
Maybe you can share theese use cases with us.
+1
I was doing conversions between numeric types within a generic context. For some conversions, I needed some additional context (e.g., an allocator). I don't think this is directly relevant, but also sometimes the conversion wouldn't be possible, and that could only be determined at runtime, so I use optional<T>s.
similar to that defined by Boost.Conversion, but ultimately I discarded
I initially constructed a generic framework this
framework in favor of the conversions being handled by a function object with signature operator()(const Srce& srce, type_tag< Dest>) -> Dest, since the conversions required additional context than that given by the Srce object.
This is the same signature Conversion uses, only it uses function overloading instead of function objects.
Yes. There aren't too many options :) Jeff, what method did you use to glue together the various function objects
into one?
I'm not sure I understand. I have a single, well-contained family of function objects that do the conversions for me, but within the context of where these conversions are actually used, one could straightforwardly replace the family of types and the corresponding family of function objects used to effect conversions between said types.
This seems similar to the Gordon suggestion. While this approach could work on most of the cases, is not able to manage with different conversion for the same couple of Source/Target types but applied to different leaves.
It's up to the generic component on whether it supports multiple conversion implementations, but I would think this unlikely. However, I think it's certainly possible for different clients using the same generic component to want different conversion implementations for a given pair of types, and that point, Boost.Conversion's universally-defined conversion implementations become useless. One wants the conversion operation to be parametrized as well as the types involved in the conversion.
The single way Boost.Conversion could take care of these specific cases
and also concept refinement is to wrap the parameter with a specific class.
But this could not be enough efficient and quite cumbersome.
I don't really see the utility of wrapping parameters in a specific class in order to select a different conversion implementation...it seems much more straightforward for generic code that utilizes conversions to simple accept one or more function objects that effect the needed conversions. - Jeff

On Aug 31, 2011, at 6:28 PM, Jeffrey Lee Hellrung, Jr. wrote:
Jeff, what method did you use to glue together the various function objects into one?
I'm not sure I understand. I have a single, well-contained family of function objects that do the conversions for me, but within the context of where these conversions are actually used, one could straightforwardly replace the family of types and the corresponding family of function objects used to effect conversions between said types.
I meant, so you have a set of conversion function objects, how do you dispatch to the right one? Or can you just dispatch on a single type in your case? I was hoping that there was a way to paste together a bunch of function objects as if they were function overloads.

On 01/09/2011 1:29, Gordon Woodhull wrote:
I was hoping that there was a way to paste together a bunch of function objects as if they were function overloads.
Create a new class that keeps references to all such function objects, and implements implicit conversions to each of them. Then you can use an instance of this class as an "overloaded function object". Agustín K-ballo Bergé.- http://talesofcpp.blogspot.com

2011/8/31 Agustín K-ballo Bergé <kaballo86@hotmail.com>
On 01/09/2011 1:29, Gordon Woodhull wrote:
I was hoping that there was a way to paste together a bunch of function objects as if they were function overloads.
Create a new class that keeps references to all such function objects, and implements implicit conversions to each of them. Then you can use an instance of this class as an "overloaded function object".
Wouldn't that result in a conversion ambiguity? How would the compiler know which function object to implicitly convert to when invoking operator()? I would imagine a generic and safe way to do what Gordon is asking is possible via Eric's can_be_called machinery. operator() for the wrapping function object checks which of the child function objects "can_be_called" with the given arguments, and if precisely one match, dispatches to the matching child, else errors. Less safe but more flexible is to just choose the first child function object that matches. - Jeff

On 01/09/2011 2:33, Jeffrey Lee Hellrung, Jr. wrote:
Create a new class that keeps references to all such function objects, and
implements implicit conversions to each of them. Then you can use an instance of this class as an "overloaded function object".
Wouldn't that result in a conversion ambiguity? How would the compiler know which function object to implicitly convert to when invoking operator()?
Of course, that technique only works as long as the function call is not ambiguous. I confess not having read the entire thread; I just assumed that this was implied by "function overloads", same overload resolution rules that work for regular functions do apply in this case. Agustín K-ballo Bergé.- http://talesofcpp.blogspot.com

2011/8/31 Agustín K-ballo Bergé <kaballo86@hotmail.com>
On 01/09/2011 2:33, Jeffrey Lee Hellrung, Jr. wrote:
Create a new class that keeps references to all such function objects, and
implements implicit conversions to each of them. Then you can use an instance of this class as an "overloaded function object".
Wouldn't that result in a conversion ambiguity? How would the compiler know which function object to implicitly convert to when invoking operator()?
Of course, that technique only works as long as the function call is not ambiguous. I confess not having read the entire thread; I just assumed that this was implied by "function overloads", same overload resolution rules that work for regular functions do apply in this case.
Hmmm...actually I'm not sure it works even in that case. The following does not compile for me if I remove the comment from "//x(0);" (MSVC9): struct X { struct Y { void operator()(int) const { } }; operator Y() const { return Y(); } }; int main(int argc, const char* argv[]) { X x; //x(0); static_cast< X::Y >(x)(0); return 0; } Is this what you had in mind, or something else? - Jeff

On 01/09/2011 3:13, Jeffrey Lee Hellrung, Jr. wrote:
The following does not compile for me if I remove the comment from "//x(0);" (MSVC9):
struct X { struct Y { void operator()(int) const { } }; operator Y() const { return Y(); } };
int main(int argc, const char* argv[]) { X x; //x(0); static_cast< X::Y>(x)(0); return 0; }
Is this what you had in mind, or something else?
Indeed, it seems I have been confused. Probably by the fact that it works for function pointers. I will take another look at the whole overloaded function object in the morning. Agustín K-ballo Bergé.- http://talesofcpp.blogspot.com

On Wed, Aug 31, 2011 at 9:29 PM, Gordon Woodhull <gordon@woodhull.com>wrote:
On Aug 31, 2011, at 6:28 PM, Jeffrey Lee Hellrung, Jr. wrote:
Jeff, what method did you use to glue together the various function objects into one?
I'm not sure I understand. I have a single, well-contained family of function objects that do the conversions for me, but within the context of where these conversions are actually used, one could straightforwardly replace the family of types and the corresponding family of function objects used to effect conversions between said types.
I meant, so you have a set of conversion function objects, how do you dispatch to the right one? Or can you just dispatch on a single type in your case?
Yeah, I always convert *to* a specific type within each function object, but the template is parametrized on the "to" type: template< class To > struct convert_functor { typedef To result_type; To operator()(const From1& from) const { ... } To operator()(const From2& from) const { ... } // etc. }; I was hoping that there was a way to paste together a bunch of function
objects as if they were function overloads.
See my other reply. - Jeff

Le 01/09/11 00:28, Jeffrey Lee Hellrung, Jr. a écrit :
On Wed, Aug 31, 2011 at 11:55 AM, Gordon Woodhull<gordon@woodhull.com>wrote:
Hi Jeff, Vicente,
Le 30/08/11 20:43, Jeffrey Lee Hellrung, Jr. a écrit :
I, too, had an application that required unrelated types to be interconverted, and generic algorithms and data structures
On Aug 30, 2011, at 4:50 PM, Vicente J. Botet Escriba wrote: that
required these conversions. Maybe you can share theese use cases with us. +1
I was doing conversions between numeric types within a generic context. For some conversions, I needed some additional context (e.g., an allocator). I don't think this is directly relevant, but also sometimes the conversion wouldn't be possible, and that could only be determined at runtime, so I use optional<T>s.
similar to that defined by Boost.Conversion, but ultimately I discarded
I initially constructed a generic framework this
framework in favor of the conversions being handled by a function object with signature operator()(const Srce& srce, type_tag< Dest>) -> Dest, since the conversions required additional context than that given by the Srce object. This is the same signature Conversion uses, only it uses function overloading instead of function objects.
Yes. There aren't too many options :) Gordon, I added the function overloading after a Jeff's suggestion.
Jeff, what method did you use to glue together the various function objects
into one?
I'm not sure I understand. I have a single, well-contained family of function objects that do the conversions for me, but within the context of where these conversions are actually used, one could straightforwardly replace the family of types and the corresponding family of function objects used to effect conversions between said types.
This seems similar to the Gordon suggestion. While this approach could work on most of the cases, is not able to manage with different conversion for the same couple of Source/Target types but applied to different leaves.
It's up to the generic component on whether it supports multiple conversion implementations, but I would think this unlikely. However, I think it's certainly possible for different clients using the same generic component to want different conversion implementations for a given pair of types, and that point, Boost.Conversion's universally-defined conversion implementations become useless. One wants the conversion operation to be parametrized as well as the types involved in the conversion.
Yes, in this case it would be better to relay on specific converters/conversions.
The single way Boost.Conversion could take care of these specific cases and also concept refinement is to wrap the parameter with a specific class. But this could not be enough efficient and quite cumbersome. I don't really see the utility of wrapping parameters in a specific class in order to select a different conversion implementation...it seems much more straightforward for generic code that utilizes conversions to simple accept one or more function objects that effect the needed conversions.
I agree that for these cases it is more natural to accept a functor. Best, Vicente

on Tue Aug 30 2011, "Jeffrey Lee Hellrung, Jr." <jeffrey.hellrung-AT-gmail.com> wrote:
Your example of converting between boost::chrono objects and boost::posix_time objects is, indeed, a real use case, so thank you. I can imagine other similar use cases, where you want objects from two independent libraries to be interconvertible. But this isn't *quite* what I was looking for. Have you (or do you know someone who has) used the framework provided by Boost.Conversion to utilize conversions in a generic setting (e.g., generic algorithms or data structures)?
I don't think that's an appropriate test for the usefulness of a library. Lots of people who never write templates use std::vector. But if you're not trying to determine utility, I am left wondering about the purpose of your question. ,---- | This remark not intended to convey any position on the library in | question. Not to be used in interstate commerce. Void where prohibited | by law. `---- -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Wed, Aug 31, 2011 at 10:18 PM, Dave Abrahams <dave@boostpro.com> wrote:
on Tue Aug 30 2011, "Jeffrey Lee Hellrung, Jr." < jeffrey.hellrung-AT-gmail.com> wrote:
Your example of converting between boost::chrono objects and boost::posix_time objects is, indeed, a real use case, so thank you. I can imagine other similar use cases, where you want objects from two independent libraries to be interconvertible. But this isn't *quite* what I was looking for. Have you (or do you know someone who has) used the framework provided by Boost.Conversion to utilize conversions in a generic setting (e.g., generic algorithms or data structures)?
I don't think that's an appropriate test for the usefulness of a library. Lots of people who never write templates use std::vector. But if you're not trying to determine utility, I am left wondering about the purpose of your question.
I feel like there's a difference between std::vector and Boost.Conversion, in the sense that Boost.Conversion seems primarily geared toward generic contexts. I'm wondering about what the experience has been with using Boost.Conversion in such contexts. std::vector has plenty of uses (understatement, probably) outside of generic contexts. I could be wrong about the scope of Boost.Conversion, though...
,---- | This remark not intended to convey any position on the library in | question. Not to be used in interstate commerce. Void where prohibited | by law. `----
[Left this in to avoid a lawsuit from Dave.] - Jeff

On Aug 29, 2011, at 12:07 PM, Jeffrey Lee Hellrung, Jr. wrote:
I'm considering writing a review, but it will necessarily be late (sometime this week?).
Thanks Jeff, that would be most helpful. With permission of the Wizards, I'm extending the review through Friday. Cheers, Gordon
participants (5)
-
Agustín K-ballo Bergé
-
Dave Abrahams
-
Gordon Woodhull
-
Jeffrey Lee Hellrung, Jr.
-
Vicente J. Botet Escriba