2016-09-15 2 views
0

Я пытаюсь играть с CRTP с пользовательским классом матрицы. Теперь я пытаюсь перегрузить оператора ostream, следуйте https://msdn.microsoft.com/en-us/library/1z2f6c2k.aspx.Перегрузка оператора ostream в пользовательском классе

Однако все, кажется, компилируется, но программа никогда не существует и ничего не печатает на экране. Я почесываю голову, как то, что происходит.

Во всяком случае, это соответствующий код (К сожалению, это немного длинный)

#ifndef EXPERIMENT_POINTERMATRIX_H 
#define EXPERIMENT_POINTERMATRIX_H 

#include <cstdlib> 
#include <ostream> 
#include "macro.h" 
namespace PM { 
    template<typename T, typename Derived> 
    class MatrixBase{ 
    public: 
     size_t nRow; 
     size_t nCol; 

     MatrixBase(const size_t nRow_,const size_t nCol_):nRow(nRow_), nCol(nCol_){} 
     Derived& derived(){ 
      return *static_cast<Derived*>(this); 
     } 
     const Derived& derived() const{ 
      return *static_cast<Derived*>(this); 
     } 

     T& operator()(const size_t i, const size_t j){ 
      CHECK_BOUND(i,j,*this); 
      return derived().operator()(i,j); 
     } 
     const T& operator()(const size_t i, const size_t j) const { 
      return const_cast<T&>(
        static_cast<const MatrixBase<T, Derived>&>(*this).operator()(i,j)); 

     } 

     inline T rows(){ 
      return nRow; 
     } 
     const T rows() const { 
      return nRow; 
     } 
     inline T cols(){ 
      return nCol; 
     } 
     const T cols() const { 
      return nCol; 
     } 
     template<typename t1, typename t2> 
     friend std::ostream& operator<<(std::ostream& os, const MatrixBase<t1, t2> & matrix); 
    }; 
    template<typename t1, typename t2> 
    std::ostream& operator<<(std::ostream& os, const MatrixBase<t1, t2>& matrix){ 

     for (size_t i =0;i<matrix.rows();i++){ 

      os << matrix(i,0); 
      if (matrix.cols()>1) { 
       for (size_t j = 1; j < matrix.cols(); j++) { 
        os << "," << matrix(i, j); 
       } 
      } 
      os << std::endl; 
     } 
     return os; 
    }; 

    template<typename T, typename Derived> 
    class Matrix : public MatrixBase<T, Matrix<T, Derived>>{ 
    public: 
     T * data; 

     Matrix(const size_t nRow, const size_t nCol):MatrixBase<T, Matrix<T, Derived>>(nRow, nCol){ 
      data = (T*) malloc(sizeof(T)*nRow*nCol); 
     } 

     ~Matrix(){ 
      free(data); 
     } 
     Derived& derived(){ 
      return *static_cast<Derived*>(this); 
     } 
     const Derived& derived() const{ 
      return *static_cast<Derived*>(this); 
     } 

     T& operator()(const size_t i, const size_t j){ 
      return derived().operator()(i,j); 
     } 


    }; 

    template<typename T, typename Derived> 
    class MatrixView : public MatrixBase<T, MatrixView<T, Derived>>{ 
    public: 
     T * data; 
     MatrixView(const size_t nRow, size_t nCol, T * other):MatrixBase<T, MatrixView<T, Derived>>(nRow, nCol), data(other){} 
     T& operator()(const size_t i, const size_t j){ 
      return derived().operator()(i,j); 
     } 
     Derived& derived(){ 
      return *static_cast<Derived*>(this); 
     } 
     const Derived& derived() const{ 
      return *static_cast<Derived*>(this); 
     } 
    }; 

    template<typename T> 
    class MatrixRowMajor: public Matrix<T, MatrixRowMajor<T>>{ 
    public: 

     MatrixRowMajor(const size_t nRow, const size_t nCol):Matrix<T, MatrixRowMajor<T>>(nRow, nCol){} 
     T& operator()(const size_t i, const size_t j){ 
      using base = MatrixBase<T, Matrix<T, MatrixRowMajor<T>>>; 
      using super = Matrix<T, MatrixRowMajor<T>>; 
      return super::data[i*base::nCol+j]; 
     } 
    }; 
    template<typename T> 
    class MatrixColMajor: public Matrix<T, MatrixColMajor<T>>{ 
    public: 
     MatrixColMajor(const size_t nRow, const size_t nCol):Matrix<T, MatrixColMajor<T>>(nRow, nCol){} 
     T& operator()(const size_t i, const size_t j){ 
      using base = MatrixBase<T, Matrix<T, MatrixColMajor<T>>>; 
      using super = Matrix<T, MatrixColMajor<T>>; 
      return super::data[i+j*base::nRow]; 
     } 
    }; 
    template<typename T> 
    class MatrixViewRowMajor : public MatrixView<T, MatrixViewRowMajor<T>>{ 
    public: 
     MatrixViewRowMajor(const size_t nRow, const size_t nCol, T* other):MatrixView<T, MatrixViewRowMajor<T>>(nRow, nCol, other){} 
     T& operator()(const size_t i, const size_t j){ 
      using base = MatrixBase<T, Matrix<T, MatrixViewRowMajor<T>>>; 
      using super = MatrixView<T, MatrixViewRowMajor<T>>; 
      return super::data[i*base::nCol+j]; 
     } 
    }; 

    template<typename T> 
    class MatrixViewColMajor : public MatrixView<T, MatrixViewColMajor<T>>{ 
    public: 
     MatrixViewColMajor(const size_t nRow, const size_t nCol, T* other):MatrixView<T, MatrixViewRowMajor<T>>(nRow, nCol, other){} 
     T& operator()(const size_t i, const size_t j){ 
      using base = MatrixBase<T, Matrix<T, MatrixViewRowMajor<T>>>; 
      using super = MatrixView<T, MatrixViewRowMajor<T>>; 
      return super::data[i+j*base::nRow]; 
     } 
}; 
} 

void test_print(){ 
    using namespace PM; 
    using namespace std; 
    MatrixRowMajor<double> matrix(10, 1); 
    for (int i =0;i<matrix.rows();i++){ 
     matrix(i,0)=1.0; 
     std::cout << "i'th entry is " <<matrix(i,0) << std::endl; //This is fine 
    } 
    std::cout << matrix; //This is not fine 
} 
#endif //EXPERIMENT_POINTERMATRIX_H 

Вся программа составлена ​​с использованием г ++ 4.9 (Благоприятная C++ 11)

EDIT: для того, чтобы проверить, является ли это проблема оператора, я создаю следующие методы (на MatrixBase):

void print(){ 
      for (size_t i =0;i<this->rows();i++){ 
       std::cout << this->operator()(i,0); 
       if (this->cols()>1) { 
        for (size_t j = 1; j < this->cols(); j++) { 
         std::cout << "," << this->operator()(i, j); 
        } 
       } 
       std::cout << std::endl; 
      } 
     } 

и вызывать методы, как matrix.print(). Это работает так, как ожидалось.

К сожалению, отладчик не дает никакой полезной информации, поскольку программа останавливается в строке os < < matrix (i, 0), и когда я останавливаю программу для извлечения информации, она говорит, что не получает фрейм (Clion as отладчик)

+0

Ошибки, когда шаблоны имеют тенденцию быть длинными и запутанными и трудно читаются и понимаются в целом, но все равно будет очень полезно, если вы можете скопировать-вставить полный вывод ошибки (как текст, полностью и без редактирования) в корпус вашего вопроса. Отформатируйте его как код. –

+0

Код ошибки отсутствует. Программа компилируется и запускается, но никогда не распечатывает ничего и никогда не выходит –

+1

Выполняйте свой код шаг за шагом в режиме отладки, чтобы увидеть стек вызовов, но похоже, что ваши вызовы 'operator()' приводят к бесконечной рекурсии. – wasthishelpful

ответ

1

(функция-член MatrixBase) operator() безоговорочно называет себя, поэтому бесконечно рекурсивна.

const T& operator()(const size_t i, const size_t j) const { 
     return const_cast<T&>(
       static_cast<const MatrixBase<T, Derived>&>(*this).operator()(i,j)); 

    } 

Эта функция хвостовой рекурсией, так что может привести к бесконечной петли, а не сбой из-за большой глубины обработки вызовов.

Не связанный с вашим вопросом, как правило, считается нецелесообразным использовать malloc() в C++ - особенно при работе с типами (например, классы C++), которые могут быть несовместимы с результатами C для пользователя вашего класса, в зависимости от тип T, может быть неопределенным. Вместо этого используйте оператор new. Еще лучше, используйте стандартный контейнер.

+0

A !!!!! Это очень глупый вопрос !!! Теперь я вижу проблему! Благодаря! –

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