Question

This is an extremely mad implementation of fixed-point arithmetic in C++. Please, no comments on how bad and pointless all this is.

As you can see, there is a base type T and a number of binary digits for the fractional part N. It is needed that FixedNum<int, A> + FixedNum<int, B> evaluated to FixedNum<int, MAX(A, B)>. Here is how I try to implement it. However, GCC says that the assignments to x in the last lines are wrong, as x is protected. What's wrong?

#define MAX(a,b) (((a)>(b))?(a):(b))

template <typename T, int N>
class FixedNum
{
    public:
        template <int N2>
        friend FixedNum& operator+(const FixedNum& f, const FixedNum& g);
        template <int N2>
        friend FixedNum& operator+=(const FixedNum& f, const FixedNum& g);
        FixedNum(T x): x (x) {}

        T num() const { return x; }
        int point() const { return N; }

    protected:
        T x;
};

template <typename T, int N, int N2>
FixedNum<T, MAX(N, N2)>& operator+(const FixedNum<T, N>& f, const FixedNum<T, N2>& g)
{
    return FixedNum<T, N>(f) += g;
}

template <typename T, int N, int N2>
FixedNum<T, MAX(N, N2)>& operator+=(const FixedNum<T, N>& f, const FixedNum<T, N2>& g)
{
#if N2 <= N
    f.x += g.x << (N-N2);
#else
    f.x <<= (N2-N);
    f.x += g.x;
#endif
}
Was it helpful?

Solution 2

Each instantiation of a template class type is a different class.
Remember that the classes actually have a different name, and are not related by inheritance.

FixedNum<int,5> is a unique name, and will be different from the class type FixedNum<int,6>.
Therefor they can't access each other's protected members.

You will have to decalare all the "similar" templated classes as friends, like this:

template<typename T, int N> friend class FixedNum;

Besides that, using preprocessor #if over there won't work like you want it to.
The preprocessor, much like its name, process BEFORE the compiler starts to process all the code. So it only evaluates MACRO values and prprocessor definitions.

OTHER TIPS

You must use a bool selector template and specialize it for N2 <= N instead of using #if #else #endif. The preprocessor won't see the template instantiation at all.

Maybe this:

#include <iostream>

template <typename T, int N>
class FixedNum
{
    public:
    FixedNum(T x): x (x) {}

    T num() const { return x; }
    int point() const { return N; }

    // A += with a FixedNum with a different N is pointless.
    FixedNum& operator+=(const FixedNum& g) {
        x += g.x;
        return *this;
    }

    protected:
    T x;
};


// A helper class to provide the result type and operation.
template <typename T, int N1, int N2>
struct FixedNumAdd
{
    typedef FixedNum<T, (N1 < N2) ? N2 : N1> result_type;
    static result_type apply(const FixedNum<T, N1>& f, const FixedNum<T, N2>& g) {
        if(N1 < N2) {
            T x = f.num();
            for(int i = N1; i < N2; ++i) x *= 10;
            return result_type(x) += g.num();
        }
        else {
            T x = g.num();
            for(int i = N2; i < N1; ++i) x *= 10;
            return result_type(x) += f.num();
        }
    }
};

template <typename T, int N1, int N2>
inline typename::FixedNumAdd<T, N1, N2>::result_type
operator + (const FixedNum<T, N1>& f, const FixedNum<T, N2>& g)
{
    return FixedNumAdd<T, N1, N2>::apply(f, g);
}

int main() {
    FixedNumAdd<int, 1, 2>::result_type result
        = FixedNum<int, 1>(11)
        + FixedNum<int, 2>(13);
    std::cout <<  double(result.num()) / 100 << std::endl;
    return 0;
}

(With C++11 and auto it would be nicer)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top