1

我有一个非常适合我需要实现的算法的矩阵类。我知道 Eigen,但它不符合我的要求,所以我必须自己做。我一直在使用 Column Major 排序,现在我也有强大的用例来使用 Row Major,所以我想用一个定义排序的额外模板参数来专门化我的模板矩阵类,但我不想打破现有的代码。

这样做的具体效果是使用模板部分特化来生成不同的两个或三个关键类方法,例如operator(int i, int j)定义不同的排序,类似的概念可以使用预处理器完成#define,但这不是很优雅,只能编译所有在一种或另一种模式下。这是我要完成的工作的草图:

enum tmatrix_order {
    COLUMN_MAJOR, ROW_MAJOR
};

/**
* Concrete definition of matrix in major column ordering that delegates most
* operations to LAPACK and BLAS functions. This implementation provides support
* for QR decomposition and fast updates. The following sequence of QR updates
* are supported:
*
* 1) [addcol -> addcol] integrates nicely with the LAPACK compact form.
* 2) [addcol -> delcol] delcols holds additional Q, and most to date R
* 3) [delcol -> delcol] delcols holds additional Q, and most to date R
* 4) [delcol -> addcol] delcols Q must also be applied to the new column
* 5) [addcol -> addrow] addrows holds additional Q, R is updated in original QR
* 6) [delcol -> addrow] addrows holds additional Q, R is updated in original QR
*/
template<typename T, tmatrix_order O = COLUMN_MAJOR>
class tmatrix {
private:
    // basic matrix structure
    T* __restrict m_data;
    int           m_rows, m_cols;     
// ...
};

template <typename T>
inline T& tmatrix<T, COLUMN_MAJOR>::operator()(int i, int j) {
  return m_data[j*m_rows + i];
}

template <typename T>
inline const T& tmatrix<T, COLUMN_MAJOR>::operator()(int i, int j) const {
  return m_data[j*m_rows + i];
}

template <typename T>
inline T& tmatrix<T, ROW_MAJOR>::operator()(int i, int j) {
  return m_data[i*m_cols + j];
}

template <typename T>
inline const T& tmatrix<T, ROW_MAJOR>::operator()(int i, int j) const {
  return m_data[i*m_cols + j];
}

但编译器会抱怨部分专业化:

/Users/bravegag/code/fastcode_project/code/src/matrix.h:227:59: error: invalid use of incomplete type 'class tmatrix<T, (tmatrix_order)0u>'
/Users/bravegag/code/fastcode_project/code/src/matrix.h:45:7: error: declaration of 'class tmatrix<T, (tmatrix_order)0u>'

但是,如果我完全专门化这些功能,如下所示,它将起作用,但这非常不灵活:

inline double& tmatrix<double, COLUMN_MAJOR>::elem(int i, int j) {
  return m_data[j*m_rows + i];
}

这是语言部分模板专业化支持问题还是我使用了错误的语法?

4

2 回答 2

3

一个可能的解决方案:

enum tmatrix_order {
  COLUMN_MAJOR, ROW_MAJOR
};

template<typename T>
class tmatrix_base {
  protected:
    // basic matrix structure
    T* __restrict m_data;
    int           m_rows, m_cols;
};     

template<typename T, tmatrix_order O = COLUMN_MAJOR>
class tmatrix : public tmatrix_base<T>{
  public:
    tmatrix() {this->m_data = new T[5];}
    T& operator()(int i, int j) {
      return this->m_data[j*this->m_rows + i];
    }
    const T& operator()(int i, int j) const {
      return this->m_data[j*this->m_rows + i];
    }
};

template<typename T>
class tmatrix<T, ROW_MAJOR> : public tmatrix_base<T>{
  public:
    tmatrix() {this->m_data = new T[5];}
    T& operator()(int i, int j) {
      return this->m_data[i*this->m_cols + j];
    }
    const T& operator()(int i, int j) const {
      return this->m_data[i*this->m_cols + j];
    }
};

int main()
{
  tmatrix<double, COLUMN_MAJOR> m1;
  m1(0, 0);
  tmatrix<double, ROW_MAJOR> m2;
  m2(0, 0);
}

这个想法是您提供完整的类定义,而不是仅提供专用类中的函数。我认为基本问题是编译器不知道该类的定义是什么。

注意:您需要this->能够访问模板化的基本成员,否则查找将失败。

注意:构造函数就在那里,所以我可以测试主函数而不会炸毁。您将需要自己的(我相信您已经拥有了)

于 2012-06-08T13:51:56.590 回答
2

我会保持简单,并这样写:

template <typename T, tmatrix_order O>
inline T& tmatrix<T, O>::operator()(int i, int j) {
  if (O == COLUMN_MAJOR) {
    return m_data[j*m_rows + i];
  } else {
    return m_data[i*m_cols + j];
  }
}

虽然语言规范不能保证,但我敢打赌,您的编译器会优化与编译时常量的比较。

于 2012-06-08T14:06:52.157 回答