2013-12-05 4 views
1

Это чрезвычайно безумная реализация арифметики с фиксированной точкой в ​​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 
} 
+0

Это правда, что 'x' защищен, и, очевидно, вы пытаетесь объявить оператор + = а друг. Но я думаю, что ваша декларация вашего друга не соответствует вашему оператору. – blackbird

+2

Я не верю, что разные специализации шаблона имеют доступ к переменным 'protected' друг друга, если специализации не являются друзьями. См. Http://stackoverflow.com/questions/11001480/templated-conversion-constructor-fails-to-access-protected-data-members – SubSevn

ответ

3

Каждое экземплярирование типа класса шаблона - это другой класс.
Помните, что классы фактически имеют другое имя и не связаны по наследству.

FixedNum<int,5> - уникальное имя и будет отличаться от типа класса FixedNum<int,6>.
Для этого они не могут получить доступ к защищенным членам друг друга.

Вам придется decalare все «подобные» шаблонные классы в качестве друзей, как это:

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

Кроме того, с помощью препроцессора #if там не будет работать, как вы хотите.
Препроцессор, как и его имя, обрабатывает ПЕРЕД компилятором, который начинает обрабатывать весь код. Поэтому он оценивает только значения MACRO и определения пропроцессора.

5

Вы должны использовать шаблон bool селектора и специализироваться его N2 <= N вместо использования #if#else#endif. Препроцессор вообще не увидит экземпляр шаблона.

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 и авто, было бы лучше)

Смежные вопросы