我有一个(基本完成的)矩阵类(稍后在这篇文章中)。如果矩阵是 1x1 矩阵,那么我想隐式转换为支持类型(例如,1x1 浮点矩阵应该转换为浮点数)。
有没有办法在不创建专业化和复制 Matrix 中的所有方法的情况下做到这一点?(例如使用类似的东西std::enable_if
?)当且仅当 ROWS == COLS == 1 时,我基本上想启用隐式转换。
template <std::size_t ROWS, std::size_t COLS = 1, typename BackingType = float>
class Matrix
{
BackingType data[ROWS][COLS];
public:
Matrix()
{
for(std::size_t rdx = 0; rdx < ROWS; ++rdx)
{
for (std::size_t cdx = 0; cdx < COLS; ++cdx)
{
data[rdx][cdx] = 0;
}
}
}
const BackingType& Member(std::size_t index) const
{
assert(index < ROWS*COLS);
return *(static_cast<BackingType*>(&data[0][0]) + index);
}
BackingType& Member(std::size_t index)
{
assert(index < ROWS*COLS);
return *(static_cast<BackingType*>(&data[0][0]) + index);
}
const BackingType& Member(std::size_t rowIndex, std::size_t colIndex) const
{
assert(rowIndex < ROWS);
assert(colIndex < COLS);
return data[rowIndex][colIndex];
}
BackingType& Member(std::size_t rowIndex, std::size_t colIndex)
{
assert(rowIndex < ROWS);
assert(colIndex < COLS);
return data[rowIndex][colIndex];
}
Matrix<COLS, ROWS, BackingType> Transpose() const
{
Matrix<COLS, ROWS, BackingType> result;
for(std::size_t rowIdx = 0; rowIdx < ROWS; rowIdx++)
{
for (std::size_t colIdx = 0; colIdx < COLS; ++colIdx)
{
result.Member(colIdx, rowIdx) = Member(rowIdx, colIdx);
}
}
return result;
}
template <std::size_t otherRows, std::size_t otherCols>
Matrix<ROWS + otherRows, COLS, BackingType> AugmentBelow(const Matrix<otherRows, otherCols, BackingType>& other)
{
static_assert(COLS == otherCols, "Columns must match for a vertical augmentation.");
Matrix<ROWS + otherRows, COLS, BackingType> result;
for (std::size_t curRow = 0; curRow < ROWS; ++curRow)
{
for (std::size_t curCol = 0; curCol < COLS; ++curCol)
{
result.Member(curRow, curCol) = Member(curRow, curCol);
}
}
for (std::size_t curRow = ROWS; curRow < (ROWS + otherRows); ++curRow)
{
for (std::size_t curCol = 0; curCol < COLS; ++curCol)
{
result.Member(curRow, curCol) = other.Member(curRow - ROWS, curCol);
}
}
return result;
}
template <std::size_t otherRows, std::size_t otherCols>
Matrix<ROWS, COLS + otherCols, BackingType> AugmentRight(const Matrix<otherRows, otherCols, BackingType>& other)
{
static_assert(ROWS == otherRows, "Rows must match for a vertical augmentation.");
Matrix<ROWS, COLS + otherCols, BackingType> result;
for (std::size_t curRow = 0; curRow < ROWS; ++curRow)
{
for (std::size_t curCol = 0; curCol < COLS; ++curCol)
{
result.Member(curRow, curCol) = Member(curRow, curCol);
}
for (std::size_t curCol = COLS; curCol < (COLS + otherCols); ++curCol)
{
result.Member(curRow, curCol) = other.Member(curRow, curCol - COLS);
}
}
return result;
}
static Matrix<ROWS, COLS, BackingType> Identity()
{
static_assert(ROWS == COLS, "Identity matrices are always square.");
Matrix<ROWS, COLS, BackingType> result;
for (std::size_t diagonal = 0; diagonal < ROWS; ++diagonal)
{
result.Member(diagonal, diagonal) = 1;
}
return result;
}
};
template <std::size_t leftRows, std::size_t leftCols, std::size_t rightRows, std::size_t rightCols, typename BackingType>
inline Matrix<leftRows, rightCols, BackingType> operator*(const Matrix<leftRows, leftCols, BackingType>& left, const Matrix<rightRows, rightCols, BackingType>& right)
{
static_assert(leftCols == rightRows, "Matrix multiplications require that the left column count and the right row count match.");
Matrix<leftRows, rightCols, BackingType> result;
for (std::size_t i = 0; i < leftRows; ++i)
{
for (std::size_t j = 0; j < rightCols; ++j)
{
BackingType curItem = 0;
for (std::size_t k = 0; k < leftCols; ++k)
{
curItem += left.Member(i, k) * right.Member(k, j);
}
result.Member(i, j) = curItem;
}
}
return result;
}
template <std::size_t rows, std::size_t cols, typename BackingType>
inline Matrix<rows, cols, BackingType> operator*(BackingType val, const Matrix<rows, cols, BackingType>& target)
{
Matrix<rows, cols, BackingType> result = target;
for (std::size_t i = 0; i < rows; ++i)
{
for (std::size_t j = 0; j < cols; ++j)
{
result *= val;
}
}
return result;
}