私は(基本的に完成した)マトリックスクラスを持っています(この記事の後半で)。マトリックスが 1x1 マトリックスの場合、バッキング タイプへの暗黙的な変換が必要です (たとえば、1x1 float マトリックスは float に変換する必要があります)。
特殊化を作成し、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;
}