B
Ben Ingram
Hi all,
I am writing a template matrix class in which the template parameters are
the number of rows and number of columns. There are a number of reasons
why this is an appropriate tradeoff for my particular application. One of the
advantages is that the _compiler_ can force inner matrix dimensions used in
multiplication to agree. A _complie-time_ error will be triggered if you
write A * B and the number of coluns in A does not equal the number of
rows in B. Here's simplified code that illustrates the concept:
template<int nRows, int nCols> class Matrix {
public:
double data[nRows][nCols];
// operator*: return this * A
template<int nNewCols> Matrix<nRows,nNewCols>
operator*(const Matrix<nCols,nNewCols> &A) const {
Matrix<nRows,nNewCols> ret;
for(int iRow = 0; iRow < nRows; iRow++) {
for(int iCol = 0; iCol < nNewCols; iCol++) {
double innerProd = 0.0;
for(int iInner = 0; iInner < nCols; iInner++) {
innerProd += data[iRow][iInner] * A.data[iInner][iCol];
}
ret.data[iRow][iCol] = innerProd;
}
}
return ret;
}
};
int main(int argc, char **argv) {
Matrix<4,3> A;
Matrix<3,1> x;
Matrix<2,1> y;
A*x; // compiler creates
// Matrix<4,1> Matrix<4,3>:
perator*(const Matrix<3,1>&)
//A*y; // compile-time error thrown since compiler can't create
// Matrix<4,1> Matrix<4,3>:
perator*(const Matrix<2,1>&)
// since inner dimensions don't agree
return 0;
}
Note that while this code works under all g++ versions I tested, from
g++-2.7 through g++-3.2, it causes an internal compiler error in MSVC++
6.
The problem with this code is that the data field must be public. Otherwise,
Matrix<4,3>:
perator* will not have access to Matrix<4,1>'s or
Matrix<3,1>'s data. Thus, I would like to make Matrix<4,1> and
Matrix<3,1> friends of Matrix<4,3>. Is this possible? If so, what's the
syntax? I tried the code below and some other variations, but they were
all incorrect. The code below generated "partial specialization
`Matrix<nRows, nNewCols>' declared `friend'" and "partial specialization
`Matrix<nCols, nNewCols>' declared `friend'" errors under g++-3.0.4 and
did not give Matrix<4,3> access to the private data of Matrix<4,1> or
of Matrix<3,1>.
template<int nRows, int nCols> class Matrix {
private:
double data[nRows][nCols];
public:
// operator*: return this * A
template<int nNewCols> Matrix<nRows,nNewCols>
operator*(const Matrix<nCols,nNewCols> &A) const {
Matrix<nRows,nNewCols> ret;
for(int iRow = 0; iRow < nRows; iRow++) {
for(int iCol = 0; iCol < nNewCols; iCol++) {
double innerProd = 0.0;
for(int iInner = 0; iInner < nCols; iInner++) {
innerProd += data[iRow][iInner] * A.data[iInner][iCol];
}
ret.data[iRow][iCol] = innerProd;
}
}
return ret;
}
template<int nNewCols> friend class Matrix<nRows,nNewCols>;
template<int nNewCols> friend class Matrix<nCols,nNewCols>;
};
int main(int argc, char **argv) {
Matrix<4,3> A;
Matrix<3,1> x;
Matrix<2,1> y;
A*x; // compiler creates
// Matrix<4,1> Matrix<4,3>:
perator*(const Matrix<3,1>&)
//A*y; // compile-time error thrown since compiler can't create
// Matrix<4,1> Matrix<4,3>:
perator*(const Matrix<2,1>&)
// since inner dimensions don't agree
return 0;
}
Can this be done and if so, how? Thanks for any help,
Ben
I am writing a template matrix class in which the template parameters are
the number of rows and number of columns. There are a number of reasons
why this is an appropriate tradeoff for my particular application. One of the
advantages is that the _compiler_ can force inner matrix dimensions used in
multiplication to agree. A _complie-time_ error will be triggered if you
write A * B and the number of coluns in A does not equal the number of
rows in B. Here's simplified code that illustrates the concept:
template<int nRows, int nCols> class Matrix {
public:
double data[nRows][nCols];
// operator*: return this * A
template<int nNewCols> Matrix<nRows,nNewCols>
operator*(const Matrix<nCols,nNewCols> &A) const {
Matrix<nRows,nNewCols> ret;
for(int iRow = 0; iRow < nRows; iRow++) {
for(int iCol = 0; iCol < nNewCols; iCol++) {
double innerProd = 0.0;
for(int iInner = 0; iInner < nCols; iInner++) {
innerProd += data[iRow][iInner] * A.data[iInner][iCol];
}
ret.data[iRow][iCol] = innerProd;
}
}
return ret;
}
};
int main(int argc, char **argv) {
Matrix<4,3> A;
Matrix<3,1> x;
Matrix<2,1> y;
A*x; // compiler creates
// Matrix<4,1> Matrix<4,3>:
//A*y; // compile-time error thrown since compiler can't create
// Matrix<4,1> Matrix<4,3>:
// since inner dimensions don't agree
return 0;
}
Note that while this code works under all g++ versions I tested, from
g++-2.7 through g++-3.2, it causes an internal compiler error in MSVC++
6.
The problem with this code is that the data field must be public. Otherwise,
Matrix<4,3>:
Matrix<3,1>'s data. Thus, I would like to make Matrix<4,1> and
Matrix<3,1> friends of Matrix<4,3>. Is this possible? If so, what's the
syntax? I tried the code below and some other variations, but they were
all incorrect. The code below generated "partial specialization
`Matrix<nRows, nNewCols>' declared `friend'" and "partial specialization
`Matrix<nCols, nNewCols>' declared `friend'" errors under g++-3.0.4 and
did not give Matrix<4,3> access to the private data of Matrix<4,1> or
of Matrix<3,1>.
template<int nRows, int nCols> class Matrix {
private:
double data[nRows][nCols];
public:
// operator*: return this * A
template<int nNewCols> Matrix<nRows,nNewCols>
operator*(const Matrix<nCols,nNewCols> &A) const {
Matrix<nRows,nNewCols> ret;
for(int iRow = 0; iRow < nRows; iRow++) {
for(int iCol = 0; iCol < nNewCols; iCol++) {
double innerProd = 0.0;
for(int iInner = 0; iInner < nCols; iInner++) {
innerProd += data[iRow][iInner] * A.data[iInner][iCol];
}
ret.data[iRow][iCol] = innerProd;
}
}
return ret;
}
template<int nNewCols> friend class Matrix<nRows,nNewCols>;
template<int nNewCols> friend class Matrix<nCols,nNewCols>;
};
int main(int argc, char **argv) {
Matrix<4,3> A;
Matrix<3,1> x;
Matrix<2,1> y;
A*x; // compiler creates
// Matrix<4,1> Matrix<4,3>:
//A*y; // compile-time error thrown since compiler can't create
// Matrix<4,1> Matrix<4,3>:
// since inner dimensions don't agree
return 0;
}
Can this be done and if so, how? Thanks for any help,
Ben