From: John Moeller (fishcorn_at_[hidden])
Date: 2008-05-15 10:40:30


Hervé Brönnimann <hervebronnimann <at> mac.com> writes:

>
> That would also have been my implementation:
>
> template <int N>
> struct positive_power
> {
> template <typename T>
> static typename tools::promote_args<T>::type result(T base)
> {
> typename tools::promote_args<T>::type power =
> positive_power<N/2>::result(base);
> return (N%2) ? base * power *power : power * power;
> }
> };
>
> with the two specializations:
>
> template <>
> struct positive_power<0>
> {
> template <typename T>
> static typename tools::promote_args<T>::type result(T base)
> {
> return 1;
> }
> };
>
> template <>
> struct positive_power<1>
> {
> template <typename T>
> static typename tools::promote_args<T>::type result(T base)
> {
> return base;
> }
> };
>
> (strictly speaking, <0> only is needed, but the compiler may not
> know to optimize multiplying by T(1), which is one criticism of
> previous post by John Moeller, who proposes essentially the same
> solution but with a factor ((N%2) ? base : 1) that I don't like).

Fair enough. I think, though, if you're going to try to make sure that
the compiler doesn't miss multiplication by 1, you may as well go all the
way and add another template parameter to capture N%2, and get rid of the
ternary statement:

template <int N, int M = N%2>
struct positive_power;

template <int N>
struct positive_power<N, 0>
{
     template <typename T>
     static typename tools::promote_args<T>::type result(T base)
     {
          typename tools::promote_args<T>::type power =
positive_power<N/2,(N/2)%2>::result(base);
          return power * power;
     }
};

template <int N>
struct positive_power<N, 1>
{
     template <typename T>
     static typename tools::promote_args<T>::type result(T base)
     {
          typename tools::promote_args<T>::type power =
positive_power<N/2,(N/2)%2>::result(base);
          return base * power * power;
     }
};

with the two specializations:

template <>
struct positive_power<0,0>
{
     template <typename T>
     static typename tools::promote_args<T>::type result(T base)
     {
          return 1;
     }
};

template <>
struct positive_power<1,1>
{
     template <typename T>
     static typename tools::promote_args<T>::type result(T base)
     {
          return base;
     }
};

Now all the compiler has to do is spit out multiplications, assuming that
things are inlined well.