Following the recent is_convertible discussion, I've put the following together:
Rationale: ~~~~~~ There has been some fairly intense discussion on boost mailing list about the is_convertible template, one suggestion was that since only expressions (and not types) are convertible to a type or not, that is_convertible should be an intrinsic binary operator whose first argument was an expression, and whose second was a type. There are two key advantages to this approach: it more closely mirrors the text of the standard, and therefore standard wording is easier to formulate, and that the result can be context sensitive: class B; class A { A(const B&); /* details omitted */ }; Here class B is convertible to A only within the scope of A; if is_convertible is a template then the one definition rule requires that is_convertible<B,A>::value have one value only, and must not be sensitive to context. On the other hand, in spite of it's failings, the is_convertible template has proven to be extremely useful in practice, and only very rarely does a corner case arise where it fails to do the right thing. The template also appears to be easily understood by end users, even if getting the standardese correct is tricky. To put this in perspective there are about 50 uses of the is_convertible template within the boost library, none of which would obviously benefit from an operator style of syntax, some examples include: lexical_cast: uses is_convertible to determine whether the source type can be implicitly converted to the destination type, if it can then the usual iostream based cast is optimised away. Named template parameters: several libraries use is_convertible to determine whether a template parameter is a particular named parameter, otherwise the parameter is treated as a positional parameter. Higher level traits: is_convertible is often used to help compose higher level traits classes; for example the lambda library uses this to calculate type promotions, this functionality could probably be more easily implemented with a typeof operator however. Static assertions: several libraries use is_convertible in conjunction with static assertions to verify that template arguments have the required properties, and to output an early, well commented error message if they do not. Likewise is_convertible has also been used (outside of boost) to ensure that code "does the right thing", for example the constructor: template <class T, class Allocator> template <class I> vector<T,Allocator>::vector<I>(I first, I last, const Allocator& a); Needs to behave differently depending upon whether type I is an iterator or a numeric type. One solution is to default initialise the object, and then perform a compiler time dispatch to different a member function depending upon whether the expression: is_convertible<I,size_type>::value && is_convertible<I,value_type>::value is true or not. The author's belief is that as far as the DR is concerned, the is_convertible template class is the right way to go; it is better understood, and has shown itself to be useful as compared to an as yet untried intrinsic operator. However implementers should be encouraged to experiment with an intrinsic convertibility operator, and this subject may need to be revisited prior to the next standard. Text: ~~~ template <class From, class To> struct is_convertible { static const bool value = implementation_defined; }; value: defined to be true only if an imaginary lvalue of type From is implicitly-convertible to type To (4.0). Special conversions involving string-literals and null-pointer constants are not considered (4.2, 4.10 and 4.11). No function-parameter adjustments (8.3.5) are made to type To when determining whether From is convertible to To: this implies that a program is ill formed if type To is a function type, and that if type To is an array type, then value must necessarily evaluate to false. The expression is_convertible<From,To>::value is ill-formed if: Type From, is a void or incomplete type (3.9). Type To, is not an object or reference type (3.9). The conversion is ambiguous, for example if type From has multiple base classes of type To (10.2). Type To is of class type and the conversion would invoke a non-public constructor of To (11.0 and 12.3.1). Type From is of class type and the conversion would invoke a non-public conversion operator of From (11.0 and 12.3.2). ~~~~ John Maddock http://ourworld.compuserve.com/homepages/john_maddock/index.htm _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost