Boost logo

Boost Users :

From: David Abrahams (dave_at_[hidden])
Date: 2006-11-12 12:23:46


"Michael Marcin" <mmarcin_at_[hidden]> writes:

> Hello,
>
> I have a fixed point math class and I want to enable some optimized operator
> overloads.
>
> for instance:
>
> fixed& fixed::operator /= ( const fixed &rhs );
> fixed& fixed::operator /= ( int n );
>
> it seems however to me that what I really want is an overload like:
>
> template< typename T >
> fixed& operator /= ( typename
> boost::enable_if<boost::is_integral<T>,T>::type n );
>
> However I can't seem to get that function considered for overload
> resolution

Because your type T there is in a nondeduced context.

You need

    template < typename T >
    boost::enable_if<boost::is_integral<T>,fixed&> operator/=(T n)

> Speaking of which I don't understand why the following doesn't work in place
> of the previous constructor.
>
> template< typename T >
> fixed::fixed( typename boost::enable_if< boost::is_integral<T>,T>::type n );

Again, nondeduced context. What you're trying to ask the compiler to
do when you call that constructor is to find T such that
enable_if<is_integral<T>,T>::type is the same as the argument type.
But there could in principle be many such Ts depending on the
definitions of enable_if and is_integral. The compiler doesn't know
that enable_if happens to be defined so that there is a unique T that
satisfies that condition, and more importantly, C++ compilers aren't
required to do that sort of deduction.

     template <class T> struct id;

     template <class T>
     void f(typename id<T>::type);

looks simple, right?

     template <class T>
     struct id { typedef int type; }; // uh-oh

     now let's

> Finally I'm using this class to replace a lot of hardcoded / macro logic and
> often as an optimization the code uses binary shifts to represent power of 2
> multiply/divides. Going forward these divides need to work with both fixed
> and floating point types so f >> 1 needs to change to f / 2. Is it possible
> to create an overload for the / and * operators that determine if the
> operand is an integral constant and is a power of 2 and use a binary shift
> internally?

The only way you'll be able to detect power-of-2-ness at overload
resolution time is if you pass the number at compile-time:

   
   // UNTESTED!
   typedef mpl::integral_c<unsigned,1> one;

   template <class N>
   struct is_power_of_2
     : mpl::or_<
           mpl::less_equal<N,one>
         , mpl::and_<
               mpl::not_<mpl::bitand<N,one> >
             , is_power_of_2<mpl::shift_right<N,one> >
>
>
   {};

   template <class T>
   enable_if<is_power_of_2<T>, int> f(T) { return 0; }

   int x = f(mpl::int_<16>()); // OK
   int y = f(mpl::int_<5>()); // compile-time error

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net