我有一个非常适合我需要实现的算法的矩阵类。我知道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];
}
这是语言部分模板特化支持问题还是我使用了错误的语法?
答案 0 :(得分: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->
才能访问模板化基础成员,否则查找将失败。
注意:构造函数就在那里,所以我可以测试主函数而不会爆炸。你需要自己的(我相信你已经拥有)
答案 1 :(得分: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];
}
}
虽然语言规范不能保证,但我敢打赌,编译器会优化与编译时常量的比较。