Compile time positive and negative powers of two I'm getting started on template meta-programming and I wrote a template to compute compile-time positive and negative float powers of 2. I would like some feedback on readability and overall code complexity as I feel like I might be defining too many structures for such a simple computation. The code has to be C++98 compatible.

// Sign of an integer
template&lt;bool b&gt; struct SIGN {static const int value = ( b * 2 ) - 1; };

// Positive powers of two (fast exponentiation)
template&lt;unsigned int N&gt; struct POW2_POS { 
    static const float value =
      POW2_POS&lt;N%2&gt;::value 
    * POW2_POS&lt;N/2&gt;::value 
    * POW2_POS&lt;N/2&gt;::value; 
};
template&lt;&gt; struct POW2_POS &lt;1&gt; { static const float value = 2.0f; };
template&lt;&gt; struct POW2_POS &lt;0&gt; { static const float value = 1.0f; };

// Negative powers of two
template&lt;unsigned int N&gt; struct POW2_NEG {static const float value = 1.0f / POW2_POS&lt;N&gt;::value; };

// Calls POW2_POS or POW2_NEG depending on boolean parameter
template&lt;bool b, unsigned int N&gt; struct POW2_SIGNED;
template&lt;unsigned int N&gt; struct POW2_SIGNED&lt;true, N&gt; { static const float value = POW2_POS&lt;N&gt;::value;};
template&lt;unsigned int N&gt; struct POW2_SIGNED&lt;false, N&gt; { static const float value = POW2_NEG&lt;N&gt;::value;};

// Integer power of two
template&lt;int N&gt; struct POW2 { 
    static const float value = POW2_SIGNED&lt;(N&gt;=0), SIGN&lt;(N&gt;=0)&gt;::value * N&gt;::value; 
};


Example program

#include &lt;iostream&gt;
int main()
{
    std::cout&lt;&lt;POW2&lt;0&gt;::value &lt;&lt;"\n";
    std::cout&lt;&lt;POW2&lt;1&gt;::value &lt;&lt;"\n";
    std::cout&lt;&lt;POW2&lt;4&gt;::value &lt;&lt;"\n";
    std::cout&lt;&lt;POW2&lt;7&gt;::value &lt;&lt;"\n";
    std::cout&lt;&lt;POW2&lt;-4&gt;::value &lt;&lt;"\n";
}


Output

1
2
16
128
0.0625
Your code is not C++98 compliant

Standards prior to C++11 only allows const integer static member initialisation (see here).

So unfortunately your code is not C++98 compliant and in fact does not compile. So technically your code is off-topic on this site. As it is not working as intended. Your code probably only compiles because you're using a compiler that has an extension to allow non integer const static members.

To get around this typically you would define a static method that returns the value. In fact, this is why std::numeric_limits&lt;T&gt;::max() is a function instead of a static member value. However these cannot be evaluated in a constant expression context. You need C++11 constexpr for that afaik.

General advice

Some general advice. Template parameters are compile time constants by definition. Any sensible compiler should do any necessary casts during compile time so you will not get a run-time penalty for using higher precision. 

For this reason I advice that you use the largest types possible in your template to get the most precision at no additional cost. I.e. change float to double and int to long long. 

You should consider wrapping the templates that are not intended for use by the user in a suitable namespace. Typically I use a nested namespace called detail.

Also identifiers in ALL_CAPS_WITH_UNDERSCORES are typically reserved for macros. So I advice against using this naming convention for your identifiers as it will confuse many readers.

Better implementation

If we restrict ourselves to the bits of the code that are C++98 compliant, then we can have a much easier implementation for the integer exponentiation.

template&lt;unsigned long long exponent&gt;
struct ipow_2{
    static const unsigned long long value = (1 &lt;&lt; exponent);
};


If you want a C++98 compliant negative exponent you can use: 

template&lt;long long exponent&gt;
struct pow_2{
    static double value(){
        if (exponent == 0) {
            return 1;
        } 
        else if (exponent &gt; 0) {
            double half = pow_2&lt;exponent/2&gt;::value();
            return (1&lt;&lt;(exponent&amp;1))*half*half;
        }
        return 1 / pow_2&lt;-exponent&gt;::value();
    };
};


But be aware that the same caveat for non-integer const initialisation still applies so it's not hugely useful in TMP for example.

If we accept use C++11 you can simplify and generalize to:

// Tail call optimization will transform this into the equivalent 
// loop
constexpr int64_t ipow_p(int64_t base, int exp, int64_t ans = 1) {
    return exp &lt; 1 ?
        ans : ipow_p(base*base, exp/2, (exp % 2) ? ans*base : ans);
}

constexpr double ipow(int base, int exp){
    return exp &gt; 0 ? ipow_p(base, exp) : 1.0 / ipow_p(base, -exp);
}


This is usable in a constant (TMP) context thanks to the constexpr qualifier and At -O2 the call will be expanded to a constant.