[conversion] ADL and templates

Hi, I've tried to add a configuration point in Boost.Conversion via overloading and ADL, but while the internal call of the library can find them using a trick that adds a parameter that contains the type of the return type, the user is not able to find them without using the same this trick, but this is too dark to be natural for user code. Next follows a simplified code of the problem. The following namespace N { struct S{}; template (*typename T*) T fct1(S const& s) { return T(s); } template (*typename T*) void fct2(T &t, S const& s) { t=s; } } void test () { N::S s1; N::S s2; fct2(s2, s1); s2=fct1(*N::S*)(s1); // (1) } Results in a compile error in (1) error: ‘fct1’ was not declared in this scope Is it standard behavior that fct1 can not be found by ADL? Thanks, Vicente P.S. Please replace (* and *) by angle brackets.

On Mon, May 30, 2011 at 1:51 PM, Vicente BOTET <vicente.botet@wanadoo.fr>wrote:
Hi,
I've tried to add a configuration point in Boost.Conversion via overloading and ADL, but while the internal call of the library can find them using a trick that adds a parameter that contains the type of the return type, the user is not able to find them without using the same this trick, but this is too dark to be natural for user code.
Next follows a simplified code of the problem. The following
namespace N { struct S{};
template (*typename T*) T fct1(S const& s) { return T(s); } template (*typename T*) void fct2(T &t, S const& s) { t=s; } }
void test () { N::S s1; N::S s2; fct2(s2, s1); s2=fct1(*N::S*)(s1); // (1) }
Results in a compile error in (1)
error: ‘fct1’ was not declared in this scope
Is it standard behavior that fct1 can not be found by ADL?
Thanks, Vicente
P.S. Please replace (* and *) by angle brackets.
AFAIK, this is standard behavior. Explicitly providing template parameters to a function call (as well as namespace qualification and putting the function name in parentheses) disables ADL. I don't think you can provide an extension framework for Boost.Conversion without the result type appearing somewhere in the customization function's function parameters. I don't really view that as any "darker" than, say, using Boost.EnableIf, or any of a number of other TMP hacks...they are all constrained from a (perhaps) more ideal syntax and form by the constraints of the language. - Jeff

Hi Jeff, Jeffrey Lee Hellrung, Jr.-2 wrote:
On Mon, May 30, 2011 at 1:51 PM, Vicente BOTET <vicente.botet@wanadoo.fr>wrote:
Hi,
I've tried to add a configuration point in Boost.Conversion via overloading and ADL, but while the internal call of the library can find them using a trick that adds a parameter that contains the type of the return type, the user is not able to find them without using the same this trick, but this is too dark to be natural for user code.
Next follows a simplified code of the problem. The following
namespace N { struct S{};
template (*typename T*) T fct1(S const& s) { return T(s); } template (*typename T*) void fct2(T &t, S const& s) { t=s; } }
void test () { N::S s1; N::S s2; fct2(s2, s1); s2=fct1(*N::S*)(s1); // (1) }
Results in a compile error in (1)
error: ‘fct1’ was not declared in this scope
Is it standard behavior that fct1 can not be found by ADL?
Thanks, Vicente
P.S. Please replace (* and *) by angle brackets.
AFAIK, this is standard behavior. Explicitly providing template parameters to a function call (as well as namespace qualification and putting the function name in parentheses) disables ADL.
Thanks for the information.
I don't think you can provide an extension framework for Boost.Conversion without the result type appearing somewhere in the customization function's function parameters.
I don't really view that as any "darker" than, say, using Boost.EnableIf, or any of a number of other TMP hacks...they are all constrained from a (perhaps) more ideal syntax and form by the constraints of the language.
There is something that is troubling me on the fact that the developer will customize the conversion function using overload and ADL, but that the user could not take advantage in a simple way of this overloading. Taking in account that Boost.Conversion needs already a customization point to take care of conversion of types in the standard library (using partial specialization) the addition of the customization point using overload doesn't make simpler the user code, neither the developers customizing the class, as it would need to choose between two customization points that doesn't make any difference. If no one find that the additional customization (via overloading) point add some benefit to the library, I will prefer to remove it (IIRC, Jeff you were the one that suggested it). This will have the advantage of making the library quite more simple without limiting his expression power. Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/conversion-ADL-and-templates-tp3561641p35... Sent from the Boost - Dev mailing list archive at Nabble.com.

Vicente Botet wrote:
There is something that is troubling me on the fact that the developer will customize the conversion function using overload and ADL, but that the user could not take advantage in a simple way of this overloading. Taking in account that Boost.Conversion needs already a customization point to take care of conversion of types in the standard library (using partial specialization) the addition of the customization point using overload doesn't make simpler the user code, neither the developers customizing the class, as it would need to choose between two customization points that doesn't make any difference.
If no one find that the additional customization (via overloading) point add some benefit to the library, I will prefer to remove it. This will have the advantage of making the library quite more simple without limiting his expression power.
I have no idea to what you're referring. I've long since lost any notion of what overloads, customization points, etc. you're discussing. Can you show, with code, what the choices are and what problems you're addressing? _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Stewart, Robert wrote:
Vicente Botet wrote:
There is something that is troubling me on the fact that the developer will customize the conversion function using overload and ADL, but that the user could not take advantage in a simple way of this overloading. Taking in account that Boost.Conversion needs already a customization point to take care of conversion of types in the standard library (using partial specialization) the addition of the customization point using overload doesn't make simpler the user code, neither the developers customizing the class, as it would need to choose between two customization points that doesn't make any difference.
If no one find that the additional customization (via overloading) point add some benefit to the library, I will prefer to remove it. This will have the advantage of making the library quite more simple without limiting his expression power.
I have no idea to what you're referring. I've long since lost any notion of what overloads, customization points, etc. you're discussing. Can you show, with code, what the choices are and what problems you're addressing?
Hi, sorry I didn't give enough information. Currently Boost.Conversion has two customization points: A- overloading of conversion::convert_to function template (*typename Target, typename Source*) Target convert_to( Source const& from, dummy::base_tag<Target> const& p=dummy::base_tag(*Target*)()); The dummy parameter is there to allows overloading on the return type. B- partial specialization of conversion::overload_workaround::convert_to struct. namespace overload_workaround { template (* typename To, typename From, class Enable = void *) struct convert_to { static To apply(const From& val); }; The default implementation of conversion::convert_to calls to an internal function that calls to convert_to (ADL) after introducing a default implementation (via using). If the user has defined an overload that is preferred to the default one, his overload is called. If there is no better overload the default one call the conversion::overload_workaround::convert_to::apply function, which by default returns Target(from). The partial specialization part is needed as we can not add overload on the std namespace. When I introduced this complex mechanism I was expecting that the user could call the convert_to function without using the boost::conversion namesapce, but this is only true if it uses explicitly the dummy parameter, which doesn't seems natural to me. So if the user needs always to call the conversion function as follows boost::conversion::convert_to(*T*)(v) Now, I don't see any advantages to maintain the customization point (A). The customization point B alone allows to make whatever can be done with both and it simplifies quite a lot the implementation. The default conversion::convert_to function needs just to call the customization point B. I suspect that after refactoring, I will rename the namespace overload_workaround by something more positive. Any suggestions? If you need more details of the current implementation, you can take a look at the header http://svn.boost.org/svn/boost/sandbox/conversion/boost/conversion/convert_t.... Hopping this would be clear for you now. Thanks for your interest, Vicente P.S. Sorry again for the angle brackets (* *) -- View this message in context: http://boost.2283326.n4.nabble.com/conversion-ADL-and-templates-tp3561641p35... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Tue, May 31, 2011 at 1:06 PM, Vicente Botet <vicente.botet@wanadoo.fr>wrote:
Stewart, Robert wrote:
Vicente Botet wrote:
There is something that is troubling me on the fact that the developer will customize the conversion function using overload and ADL, but that the user could not take advantage in a simple way of this overloading. Taking in account that Boost.Conversion needs already a customization point to take care of conversion of types in the standard library (using partial specialization) the addition of the customization point using overload doesn't make simpler the user code, neither the developers customizing the class, as it would need to choose between two customization points that doesn't make any difference.
If no one find that the additional customization (via overloading) point add some benefit to the library, I will prefer to remove it. This will have the advantage of making the library quite more simple without limiting his expression power.
I have no idea to what you're referring. I've long since lost any notion of what overloads, customization points, etc. you're discussing. Can you show, with code, what the choices are and what problems you're
addressing?
Hi,
sorry I didn't give enough information.
Yes, thanks for this, I was wondering myself as well :) Currently Boost.Conversion has two customization points:
A- overloading of conversion::convert_to function
template (*typename Target, typename Source*) Target convert_to( Source const& from, dummy::base_tag<Target> const& p=dummy::base_tag(*Target*)());
The dummy parameter is there to allows overloading on the return type.
This signature of convert_to is *not* the signature that conversion::convert_to uses, right? I assume this is just the signature of the customization point. Also, is there a need for the second parameter to be defaulted? B- partial specialization of conversion::overload_workaround::convert_to
struct.
namespace overload_workaround { template (* typename To, typename From, class Enable = void *) struct convert_to { static To apply(const From& val); };
The default implementation of conversion::convert_to calls to an internal function that calls to convert_to (ADL) after introducing a default implementation (via using). If the user has defined an overload that is preferred to the default one, his overload is called. If there is no better overload the default one call the conversion::overload_workaround::convert_to::apply function, which by default returns Target(from).
The partial specialization part is needed as we can not add overload on the std namespace.
Fair enough.
When I introduced this complex mechanism I was expecting that the user could call the convert_to function without using the boost::conversion namesapce, but this is only true if it uses explicitly the dummy parameter, which doesn't seems natural to me.
I'm confused. You want the user to be able to call their own customization function directly without the use of a dummy parameter, by-passing boost::conversion::convert_to? I'm not sure I see the point... So if the user needs always to call the conversion function as follows
boost::conversion::convert_to(*T*)(v)
I don't see what's wrong with that...
Now, I don't see any advantages to maintain the customization point (A).
Well, (A) puts the customization within the user's namespace, while (B) requires opening the overload_workaround (or whatever) namespace. (A) only requires defining a function, while (B) requires specializing a struct and defining a member function. They both seem to achieve the same affect, but from the user's POV, (A) seems simpler. The customization point B alone allows to make whatever can be done with
both and it simplifies quite a lot the implementation.
"quite a lot" seems like a bit of an overstatement, although maybe you're speaking relative to the library as a whole. How much code accounts for the difference between allowing (A) and removing (A) altogether?
The default conversion::convert_to function needs just to call the customization point B.
Correct. The only thing (A) offers is (maybe) simplicity over (B).
I suspect that after refactoring, I will rename the namespace overload_workaround by something more positive. Any suggestions?
Or you could rename the convert_to struct to something else. Perhaps you should look in other Boost libraries to see how customization points are structured (Boost.MPL, Boost.Fusion, Boost.Spirit, and possibly Boost.Phoenix come to mind).
If you need more details of the current implementation, you can take a look at the header
http://svn.boost.org/svn/boost/sandbox/conversion/boost/conversion/convert_t... .
Hopping this would be clear for you now.
Thanks for your interest, Vicente
P.S. Sorry again for the angle brackets (* *)
One thing I wonder is: Suppose we have two classes from two different libraries, TypeA from LibraryA and TypeB from LibraryB, and we wish to define a conversion operation from TypeA to TypeB via Boost.Conversion. Does Boost.Conversion specify which library should contain this operation? I would suspect it couldn't, which makes me think there should be 2 levels of customization. For example, the first level of customization is defined by LibraryX when TypeX is the From type, and the second level of customization is defined by LibraryX when TypeX is the To type (X = A or B). Thus, if LibraryA provides a customization to convert TypeA to TypeB, but LibraryB likewise provides a customization to convert TypeA to TypeB, the customization in LibraryA is used unambiguously. - Jeff

Jeffrey Lee Hellrung, Jr.-2 wrote:
On Tue, May 31, 2011 at 1:06 PM, Vicente Botet <vicente.botet@wanadoo.fr>wrote:
Stewart, Robert wrote:
Vicente Botet wrote:
There is something that is troubling me on the fact that the developer will customize the conversion function using overload and ADL, but that the user could not take advantage in a simple way of this overloading. Taking in account that Boost.Conversion needs already a customization point to take care of conversion of types in the standard library (using partial specialization) the addition of the customization point using overload doesn't make simpler the user code, neither the developers customizing the class, as it would need to choose between two customization points that doesn't make any difference.
If no one find that the additional customization (via overloading) point add some benefit to the library, I will prefer to remove it. This will have the advantage of making the library quite more simple without limiting his expression power.
I have no idea to what you're referring. I've long since lost any
notion
of what overloads, customization points, etc. you're discussing. Can you show, with code, what the choices are and what problems you're addressing?
Hi,
sorry I didn't give enough information.
Yes, thanks for this, I was wondering myself as well :)
Currently Boost.Conversion has two customization points:
A- overloading of conversion::convert_to function
template (*typename Target, typename Source*) Target convert_to( Source const& from, dummy::base_tag<Target> const& p=dummy::base_tag(*Target*)());
The dummy parameter is there to allows overloading on the return type.
This signature of convert_to is *not* the signature that conversion::convert_to uses, right? I assume this is just the signature of the customization point.
Also, is there a need for the second parameter to be defaulted?
You are right. The preceding was the signature of the convert_to function. The customization point uses instead a more specific type type_tag, which derives from base_tag. template (*typename Target, typename Source*) Target convert_to( Source const& from, dummy::type_tag<Target> const& p); This as you know is needed to avoid infinite recursion, when the boost::conversion is is introduced via a using statement. This is the kind of complexity I want to avoid.
B- partial specialization of conversion::overload_workaround::convert_to
struct.
namespace overload_workaround { template (* typename To, typename From, class Enable = void *) struct convert_to { static To apply(const From& val); };
The default implementation of conversion::convert_to calls to an internal function that calls to convert_to (ADL) after introducing a default implementation (via using). If the user has defined an overload that is preferred to the default one, his overload is called. If there is no better overload the default one call the conversion::overload_workaround::convert_to::apply function, which by default returns Target(from).
The partial specialization part is needed as we can not add overload on the std namespace.
Fair enough.
When I introduced this complex mechanism I was expecting that the user could call the convert_to function without using the boost::conversion namesapce, but this is only true if it uses explicitly the dummy parameter, which doesn't seems natural to me.
I'm confused. You want the user to be able to call their own customization function directly without the use of a dummy parameter, by-passing boost::conversion::convert_to? I'm not sure I see the point...
It would need to use the dummy parameter. convert_to(v,boost::conversion::type_tag(*T*)());
So if the user needs always to call the conversion function as follows
boost::conversion::convert_to(*T*)(v)
I don't see what's wrong with that...
Now, I don't see any advantages to maintain the customization point (A).
Well, (A) puts the customization within the user's namespace, while (B) requires opening the overload_workaround (or whatever) namespace. (A) only requires defining a function, while (B) requires specializing a struct and defining a member function. They both seem to achieve the same affect, but from the user's POV, (A) seems simpler.
Maybe it is simple once the user has understood the mechanism, but the mechanism is more complex.
The customization point B alone allows to make whatever can be done with
both and it simplifies quite a lot the implementation.
"quite a lot" seems like a bit of an overstatement, although maybe you're speaking relative to the library as a whole. How much code accounts for the difference between allowing (A) and removing (A) altogether?
Really, not too much. But makes the customization point from been simple to been quite complex. If we take in account some of the other functions like assign_to, try_convert_to, convert_or_fallback, should these functions be customizable?
The default conversion::convert_to function needs just to call the customization point B.
Correct. The only thing (A) offers is (maybe) simplicity over (B).
I suspect that after refactoring, I will rename the namespace overload_workaround by something more positive. Any suggestions?
Or you could rename the convert_to struct to something else. Perhaps you should look in other Boost libraries to see how customization points are structured (Boost.MPL, Boost.Fusion, Boost.Spirit, and possibly Boost.Phoenix come to mind).
I will do.
If you need more details of the current implementation, you can take a look at the header
http://svn.boost.org/svn/boost/sandbox/conversion/boost/conversion/convert_t... .
Hopping this would be clear for you now.
Thanks for your interest, Vicente
P.S. Sorry again for the angle brackets (* *)
One thing I wonder is: Suppose we have two classes from two different libraries, TypeA from LibraryA and TypeB from LibraryB, and we wish to define a conversion operation from TypeA to TypeB via Boost.Conversion. Does Boost.Conversion specify which library should contain this operation? I would suspect it couldn't, which makes me think there should be 2 levels of customization. For example, the first level of customization is defined by LibraryX when TypeX is the From type, and the second level of customization is defined by LibraryX when TypeX is the To type (X = A or B). Thus, if LibraryA provides a customization to convert TypeA to TypeB, but LibraryB likewise provides a customization to convert TypeA to TypeB, the customization in LibraryA is used unambiguously.
- Jeff
This is the major problem these conversion functions could introduce and maybe the reason the standard doesn't allows the free function conversion operator and assignment operator. We can find two pieces of source code customizing the same conversion. But this is a more general problem. Think for example to the binary operator+(). This operator can be overloaded by two libraries with the same LHS and RHS types, and the program will be ill formed. Which library should provide the overloading? I have no response to this. The major advantage of having a single customization point is that the compiler can detect the ambiguity. The major problem of a single customization point in case of conflict, is that the single way to avoid the conflict is to be able to don't include one of the definitions. Your two levels proposition don't work always as it suppose that the conversion between TypeA and TypeB will be done either by libraryA or libraryB. The common case is that it will be libraryC which will include the conversion as if a conversion between TypeA and TypeB doesn't exists is because they don't know each other. So the problem is moved to how libraryC and libraryD use these customization points. Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/conversion-ADL-and-templates-tp3561641p35... Sent from the Boost - Dev mailing list archive at Nabble.com.

Vicente Botet wrote: [with minor editing by me]
Currently Boost.Conversion has two customization points:
A- overloading of conversion::convert_to function
template <typename Target, typename Source> Target convert_to( Source const& from, dummy::type_tag<Target> const&);
The dummy parameter is there to allows overloading on the return type.
B- partial specialization of conversion::overload_workaround::convert_to struct.
namespace overload_workaround { template < typename To , typename From , class Enable = void > struct convert_to { static To apply(const From& val); };
The default implementation of conversion::convert_to calls to an internal function that calls to convert_to (ADL) after introducing a default implementation (via using). If the user has defined an overload that is preferred to the default one, his overload is called. If there is no better overload the default one call the conversion::overload_workaround::convert_to::apply function, which by default returns Target(from).
The partial specialization part is needed as we can not add overload on the std namespace.
That is quite complex because of the two levels involved.
When I introduced this complex mechanism I was expecting that the user could call the convert_to function without using the boost::conversion namespace, but this is only true if it uses explicitly the dummy parameter, which doesn't seems natural to me.
Agreed.
So if the user needs always to call the conversion function as follows
boost::conversion::convert_to<T>(v)
Now, I don't see any advantages to maintain the customization point (A).
Agreed.
The customization point B alone allows to make whatever can be done with both and it simplifies quite a lot the implementation. The default conversion::convert_to function needs just to call the customization point B.
Having just one CP is better. Sure, PTS is less obvious than overloading a function template, but having to know about both mechanisms and which is necessary in various circumstances, makes the whole mechanism more complicated than it should be.
I suspect that after refactoring, I will rename the namespace overload_workaround by something more positive. Any suggestions?
namespace boost { namespace conversion { template <class Target, class Source, class Enable = void> struct converter { Target operator (Source const &) const; }; } } Note that I'm suggesting boost::conversion::converter<Target,Source,Enable> as the name and I'm suggesting s/apply/operator ()/ to make it a function object. These alterations mean that there is now a function object interface for effecting conversions from Source to Target which is the sole point of customization for all such conversions in the library. BTW, it might be wise to make the primary specialization fail, perhaps through the use of BCCL in the convert_to function template. _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Stewart, Robert wrote:
Vicente Botet wrote:
Having just one CP is better. Sure, PTS is less obvious than overloading a function template, but having to know about both mechanisms and which is necessary in various circumstances, makes the whole mechanism more complicated than it should be.
Glad to see that we agree here.
I suspect that after refactoring, I will rename the namespace overload_workaround by something more positive. Any suggestions?
namespace boost { namespace conversion { template <class Target, class Source, class Enable = void> struct converter { Target operator (Source const &) const; }; } }
Note that I'm suggesting boost::conversion::converter<Target,Source,Enable> as the name and I'm suggesting s/apply/operator ()/ to make it a function object. These alterations mean that there is now a function object interface for effecting conversions from Source to Target which is the sole point of customization for all such conversions in the library.
Yes, this could be a valid possibility. I will need to fix names for the other function objects associated to assign_to (assigner?), try_convert_to (try_converter), ... Or shouldn't the library provide CP for all the operations?
BTW, it might be wise to make the primary specialization fail, perhaps through the use of BCCL in the convert_to function template.
Yes, this could be done adding a dependency on BCCL. If others think this is a must I would try to include it conditionally. Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/conversion-ADL-and-templates-tp3561641p35... Sent from the Boost - Dev mailing list archive at Nabble.com.

Vicente Botet wrote:
Stewart, Robert wrote:
Vicente Botet wrote:
namespace boost { namespace conversion { template <class Target, class Source, class Enable = void> struct converter { Target operator ()(Source const &) const; }; } }
Note that I'm suggesting boost::conversion::converter<Target,Source,Enable> as the name and I'm suggesting s/apply/operator ()/ to make it a function object. These alterations mean that there is now a function object interface for effecting conversions from Source to Target which is the sole point of customization for all such conversions in the library.
Yes, this could be a valid possibility. I will need to fix names for the other function objects associated to assign_to (assigner?), try_convert_to (try_converter), ... Or shouldn't the library provide CP for all the operations?
There should be one place to effect customization for all of the APIs supported by the library. The converter interface above would need to throw an exception to indicate a failure, so perhaps instead it should be: bool operator ()(Target &, Source const &) const; That would support the try API directly while those that throw an exception would do so if the conversion returns false. Obviously, that avoids the need for Target to be Copyable, if not using a wrapper function that requires it, but it does mean that Target must be DefaultConstructible or that there be a CP for providing a default value (as we've discussed before). Perhaps it would be better if the function object interface and the customization point were split: template <class Target, class Source, class Enable = void> struct converter { Target operator ()(Source const & _source) const { Target result; if (custom_converter<Target,Source>::apply(result, _source)) { return result; } throw exception; } }; template <class Target, class Source> struct custom_converter { static bool apply(Target &, Source const &); }; A PTS of converter that tests Enable, however you intended that to work, would be provided by the library, too. Both specializations would defer to custom_converter<Target,Source>::apply() to do the conversion. That means the CP isn't concerned with the Enable template parameter or with throwing exceptions. Obviously, the try API could be written to catch exceptions and return false while the CP could be this instead: static Target apply(Source const &); That permits those customizing a particular conversion to throw whatever exceptions they like. I'm not sure which I prefer. The flexibility of throwing custom exceptions is nice, but absorbing exceptions in order to return false from the try API seems heavy handed. _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Stewart, Robert wrote:
Vicente Botet wrote:
Stewart, Robert wrote:
Vicente Botet wrote:
namespace boost { namespace conversion { template <class Target, class Source, class Enable = void> struct converter { Target operator ()(Source const &) const; }; } }
Note that I'm suggesting boost::conversion::converter<Target,Source,Enable> as the name and I'm suggesting s/apply/operator ()/ to make it a function object. These alterations mean that there is now a function object interface for effecting conversions from Source to Target which is the sole point of customization for all such conversions in the library.
Yes, this could be a valid possibility. I will need to fix names for the other function objects associated to assign_to (assigner?), try_convert_to (try_converter), ... Or shouldn't the library provide CP for all the operations?
There should be one place to effect customization for all of the APIs supported by the library. The converter interface above would need to throw an exception to indicate a failure, so perhaps instead it should be:
bool operator ()(Target &, Source const &) const;
That would support the try API directly while those that throw an exception would do so if the conversion returns false. Obviously, that avoids the need for Target to be Copyable, if not using a wrapper function that requires it, but it does mean that Target must be DefaultConstructible or that there be a CP for providing a default value (as we've discussed before).
Each operation can be applied to types with different restrictions. It is clear that convert_to can only be used for types that are CopyConstructible. The specific implementation could have other requirements. In particular the default one requires the expression Target(source) to be valid. The preceding interface corresponds to the try_assign_to function and the interface doesn't have any requirements on the target type, except if the target should not be modified when the conversion fails. In this case the implementation will impose more requirements CopyConstructible. Again each specific implementation have its owns requirements.
Perhaps it would be better if the function object interface and the customization point were split:
template <class Target, class Source, class Enable = void> struct converter { Target operator ()(Source const & _source) const { Target result; if (custom_converter<Target,Source>::apply(result, _source)) { return result; } throw exception; } };
template <class Target, class Source> struct custom_converter { static bool apply(Target &, Source const &); };
I don't think the default implementation of converter should use a function that needs to use a try-catch block to hide the possible exception thrown during the conversion.
A PTS of converter that tests Enable, however you intended that to work, would be provided by the library, too. Both specializations would defer to custom_converter<Target,Source>::apply() to do the conversion. That means the CP isn't concerned with the Enable template parameter or with throwing exceptions.
Sorry, I don't understand what do you want to do with Enable.
Obviously, the try API could be written to catch exceptions and return false while the CP could be this instead:
static Target apply(Source const &);
That permits those customizing a particular conversion to throw whatever exceptions they like.
This correspond to the current implementation of try_convert_to.
I'm not sure which I prefer. The flexibility of throwing custom exceptions is nice, but absorbing exceptions in order to return false from the try API seems heavy handed.
I think we can resume that having a single customization point for all the operations would not be enough open, and that we need CP for all the operations. The question now is what is the default behavior for each one of the operations. On the current implementation all the operations use directly or indirectly the convert CP. I will add on the documentation the requirements for each one of the implementations. I will use the Enable parameter each time the requirements can be expresed using a trait meta-function. Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/conversion-ADL-and-templates-tp3561641p35... Sent from the Boost - Dev mailing list archive at Nabble.com.

Vicente Botet wrote:
Stewart, Robert wrote:
Vicente Botet wrote:
Stewart, Robert wrote:
Note that I'm suggesting boost::conversion::converter<Target,Source,Enable> as the name and I'm suggesting s/apply/operator ()/ to make it a function object. These alterations mean that there is now a function object interface for effecting conversions from Source to Target which is the sole point of customization for all such conversions in the library.
Yes, this could be a valid possibility. I will need to fix names for the other function objects associated to assign_to (assigner?), try_convert_to (try_converter), ... Or shouldn't the library provide CP for all the operations?
There should be one place to effect customization for all of the APIs supported by the library. The converter interface above would need to throw an exception to indicate a failure, so perhaps instead it should be:
bool operator ()(Target &, Source const &) const;
That would support the try API directly while those that throw an exception would do so if the conversion returns false. Obviously, that avoids the need for Target to be Copyable, if not using a wrapper function that requires it, but it does mean that Target must be DefaultConstructible or that there be a CP for providing a default value (as we've discussed before).
Each operation can be applied to types with different restrictions. It is clear that convert_to can only be used for types that are CopyConstructible. The specific implementation could have other requirements. In particular the default one requires the expression Target(source) to be valid.
OK, but you should minimize the variations, I imagine.
The preceding interface corresponds to the try_assign_to function
Yes.
and the interface doesn't have any requirements on the target type, except if the target should not be modified when the conversion fails.
That's not a requirement on Target, which is what I was referring to.
Perhaps it would be better if the function object interface and the customization point were split:
template < class Target , class Source , class Enable = void
struct converter { Target operator ()(Source const & _source) const { Target result; if (custom_converter<Target,Source>:: apply(result, _source)) { return result; } throw exception; } };
template <class Target, class Source> struct custom_converter { static bool apply(Target &, Source const &); };
I don't think the default implementation of converter should use a function that needs to use a try-catch block to hide the possible exception thrown during the conversion.
This version was supposed to throw nothing. Doing so would mean that the try API could use it directly rather than having to absorb exceptions.
A PTS of converter that tests Enable, however you intended that to work, would be provided by the library, too. Both specializations would defer to custom_converter<Target,Source>::apply() to do the conversion. That means the CP isn't concerned with the Enable template parameter or with throwing exceptions.
Sorry, I don't understand what do you want to do with Enable.
If Enable is void, then converter<Target,Source,void>::operator () calls custom_converter<Target,Source>::apply(). However, if Enable is not void, then converter<Target,Source,Enable> must determine whether to permit the conversion. If so, operator () calls custom_converter<Target,Source>::apply(). If not, I suppose it's supposed to be a compilation error to support SFINAE?
Obviously, the try API could be written to catch exceptions and return false while the CP could be this instead:
static Target apply(Source const &);
That permits those customizing a particular conversion to throw whatever exceptions they like.
This correspond to the current implementation of try_convert_to.
Didn't you say you didn't like that, above?
I'm not sure which I prefer. The flexibility of throwing custom exceptions is nice, but absorbing exceptions in order to return false from the try API seems heavy handed.
I think we can resume that having a single customization point for all the operations would not be enough open, and that we need CP for all the operations.
Based upon what I know presently, I don't agree. It would be much nicer for those using the library to have a single place to implement their conversion logic and for the library to use that, appropriately, to implement all of the supported APIs. There could well be something I've lost track of or never knew that requires multiple CPs, but I'd hate to think that some of the APIs could be customized for some new UDT, while others would be left unimplemented until some user happens to use one of the APIs not customized.
The question now is what is the default behavior for each one of the operations.
On the current implementation all the operations use directly or indirectly the convert CP.
If that's so, why do you say that each must have its own CP?
I will add on the documentation the requirements for each one of the implementations. I will use the Enable parameter each time the requirements can be expresed using a trait meta-function.
That would mean that, for a given UDT, SFINAE would remove various APIs from consideration, possibly leaving none. A more meaningful error message would be possible using BCCL to assert that the Target satisfies the required concept(s). _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.
participants (4)
-
Jeffrey Lee Hellrung, Jr.
-
Stewart, Robert
-
Vicente Botet
-
Vicente BOTET