复杂的运算符重载和模板

时间:2013-12-05 15:04:11

标签: c++ templates operator-overloading friend

这是C ++中非常疯狂的定点运算实现。请不要评论这是多么糟糕和毫无意义。

如您所见,小部分T基本类型N 二进制数字。需要FixedNum<int, A> + FixedNum<int, B>评估为FixedNum<int, MAX(A, B)>.以下是我尝试实现它的方法。但是,GCC表示最后一行中x的分配是错误的,因为x受到保护。怎么了?

#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
}

3 个答案:

答案 0 :(得分:5)

您必须使用bool选择器模板并将其专门用于N2 <= N,而不是使用#if #else #endif。预处理器根本不会看到模板实例化。

答案 1 :(得分:3)

模板类类型的每个实例化都是不同的类 请记住,这些类实际上具有不同的名称,并且与继承无关。

FixedNum<int,5>是一个唯一的名称,与类型FixedNum<int,6>不同 因此,他们无法访问彼此受保护的成员。

你必须将所有“类似”模板化的课程视为朋友,如下所示:

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

除此之外,使用预处理器 #if 就不会像你想要的那样工作。
在编译器开始处理所有代码之前,预处理器与其名称非常相似。所以它只评估MACRO值和prprocessor定义。

答案 2 :(得分:0)

也许这个:

#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;
}

(使用C ++ 11和auto会更好)