[enable_if][type_traits] Overload resolution question
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 instead it goes through the following constructor and calls the /= that takes a const fixed &. template< typename T > fixed::fixed( T n, typename boost::enable_if< boost::is_integral<T> >::type* = 0 ); 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 ); 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? Thanks, Michael Marcin
"Michael Marcin" <mmarcin@method-solutions.com> 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
David Abrahams <dave@boost-consulting.com> writes:
"Michael Marcin" <mmarcin@method-solutions.com> 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)
Whoops template < typename T > typename boost::enable_if<boost::is_integral<T>,fixed&>::type operator/=(T n) Sorry. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
David Abrahams <dave@boost-consulting.com> writes:
"Michael Marcin" <mmarcin@method-solutions.com> 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)
Whoops
template < typename T > typename boost::enable_if<boost::is_integral<T>,fixed&>::type operator/=(T n)
Sorry.
Thank you. It works and makes sense now because of your explanations. I've been working for a year now using C++ almost exclusively and there is still so much left to learn *sigh*. - Michael Marcin
"Michael Marcin" <mmarcin@method-solutions.com> writes:
Thank you. It works and makes sense now because of your explanations. I've been working for a year now using C++ almost exclusively and there is still so much left to learn *sigh*.
You're welcome. James Dennett reminded me off-list that there's a trick for doing power-of-2 detection: (n>0 and (n&(n-1))==0) // something like this template <class N> struct is_power_of_2 : mpl::and< mpl::greater<N,mpl::int_<0> > , mpl::equal_to< typename mpl::bitand< N , typename mpl::prior<N>::type >::type , mpl::int<0> > > {}; -- Dave Abrahams Boost Consulting www.boost-consulting.com
On 11/11/06, Michael Marcin <mmarcin@method-solutions.com> wrote: ... 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?
If, in the end, the thing you are shifting is an integer type, the compiler will do the '/ 2' => '>> 1' substitution for you. So don't worry about it. Thanks,
Michael Marcin
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (3)
-
David Abrahams
-
Gottlob Frege
-
Michael Marcin