Boost logo

Boost :

From: Brian McNamara (lorgon_at_[hidden])
Date: 2004-02-25 18:56:07


On Wed, Feb 25, 2004 at 04:41:42PM -0600, Max Motovilov wrote:
> [Proposal, Part I]
>
> Providing a facility that simplifies arithmetic type promotions for D.A.T.s.
> None of the examples above currently provide it, which means that you cannot
> expect
>
> std::complex<float>( 1, 0 ) + std::complex<double>( 0, 1 )
>
> to yield std::complex<double>( 1, 1 ). So, expressions on D.A.T.s with mixed
> base types do not really behave the way the built-in numeric types do, even
> though the individual values can be converted from one instance of the same
> D.A.T. to another.
>
> In the ideal world, one should be able to write:
>
> template< typename T1, typename T2 >
> foo< typeof( T1() + T2() ) >
> operator+( const foo<T1>&, const foo<T2>& );
>
> and then implement operator+ the way it is normally implemented for foo<T>,
> first converting foo<T1> and foo<T2> to foo< typeof< T1() + T2() >. I
> intentionally leave out the optimization issues such as defining operator+
> in terms of operator+= etc. However, without typeof(), it would be nice to
> have a library solution yielding similar result, for example:
>
> template< typename T1, typename T2 >
> foo< promoted_type< T1, T2, std::plus > >
> operator+( const foo<T1>&, const foo<T2>& );
>
> The third argument of promoted_type<> could be any kind of tag value or type
> associated with the type of arithmetic operation. Templates std::plus,
> std::minus, std::multiplies, std::divides and std::modulus do not cover the
> entire range of C++ arithmetic operations so some other tags may work
> better. The implementation of promoted_type will obviously be based on
> partial specializations along with a limited typeof() facility with the
> assumption that T1 op T2 always yields either T1 or T2 (which is the case
> for built-in base types). Here is a quick and dirty implementation for only
> one operation, operator+:

See, e.g.
   http://www.boost.org/libs/lambda/doc/ar01s06.html
operator-tag representations as well as the logic that "when combining
float and double, promote both to double" already exist somewhere in
Boost (ask Joel or Jaakko, I dunno the details), so reuse those.

...
> template<
> typename T1, typename T2,
> template< typename _ > class Tag
> > struct promoted_type;

My hunch is that this bit will work better if you use MPL (rather than
have template-template parameters, you can treat the class as a
metafunction (e.g. std::complex<_1>) which can be "apply"ed.

> template< typename T1, typename T2 > struct promoted_type< T1, T2, std::plus
> >
> {
> enum { tag = sizeof( typeof_one_of_two<T1,T2>::typeof_fun( T1() +
> T2() ) ) };
> typedef typename typeof_one_of_two<T1,T2>::select_type< tag >::type
> type;
> };

Also, here you presume default constructors for T1 and T2; make sure the
actual implementation avoid this.

> Going further, we might want to add type-promoting arithmetics to existing
> DATs that do not provide it. The best I could think of so far is introducing
> overly generic template operators into global namespace, along with a
> mechanism based on boost::enable_if to restrict their use to specific
> parameter templates. The model implementation follows. I find it ugly, but
> perhaps a better one may be immediately obvious to somebody else.
...
> template< typename T1, typename T2, template< typename _ > class DAT >
> inline typename boost::disable_if_c<
> do_not< promote_sum< DAT > >::value,
> DAT< typename promoted_type<T1,T2,std::plus>::type >
> >::type
> operator+( const DAT<T1>& a, const DAT<T2>& b )
> {
> typedef typename DAT< promoted_type<T1,T2,std::plus>::type > T;
> return T( a ) + T( b );
> }

I'm sure there's a bit to hammer out with respect to the details, but
yeah, I like the idea of using a specialization to say "I want this
trick enabled" and then using enable_if with a general operator@()
template to do the automatic promotion work.

> Well, if anybody got this far, I have to confess that I'm not sure what to
> do with all this. The first part looks so trivial I may have well overlooked
> an equivalent facility in one of the existing Boost libraries. If I haven't,
> it hardly deserves a separate library, but I'm not sure which existing one
> would be a good place for it. The second part looks like it belongs in
> boost::operators, assuming that its benefits outweigh the dangers of
> introducing very generic operators into global namespace (or is there a way
> to do it otherwise and still get C++ to find the operator definitions?). Let
> me know whether it will be worthwhile to develop proposed facilities for
> subsequent Boostification.

There may already be some way to do this in Boost, I dunno. I think
no, but I also think that sufficient related infrastructure is already
there to do most of the work; this is probably easy to build on top, and
if you "do it right", it will generalize really nicely.

-- 
-Brian McNamara (lorgon_at_[hidden])

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk