0

私は(基本的に完成した)マトリックスクラスを持っています(この記事の後半で)。マトリックスが 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;
}
4

4 に答える 4

7

別の方法:

template<typename T, int Rows, int Cols>
struct matrix {
    template<
        // we need to 'duplicate' the template parameters
        // because SFINAE will only work for deduced parameters
        // and defaulted parameters count as deduced
        int R = Rows
        , int C = Cols

        // C++11 allows the use of SFINAE right here!
        , typename = typename std::enable_if<
            (R == 1 && C == 1)
        >::type
    >
    operator T() const;
};
于 2011-10-08T07:56:01.610 に答える
6

conditionalではなくを使用した大雑把なハックアラウンドを次に示しenable_ifます。

#include <functional>

template <typename T, int N, int M>
struct Matrix
{
  struct IncompleteType;

  T buf[N * M];
  operator typename std::conditional<N == 1 && M == 1, T, IncompleteType<T>>::type () const
  {
    return buf[0];
  }
};

いくつかの作業を行うことで、コンパイラ エラーをもう少し意味のあるものにすることもできます。

于 2011-10-07T23:28:57.707 に答える
3
template <typename T, int N, int M>
struct Matrix
{    
  T buf[N * M];
  operator typename std::conditional<N == 1 && M == 1, T, void>::type () const
  {
    return buf[0];
  }
};

この場合、定義する必要はありませんIncompleteTypevoid型を持つ関数はvoid値を返すべきではありませんが、何かを返すため、sufficesを使用することで十分です。これにより置換が失敗し、SFINAE が開始されます。

于 2013-10-17T18:23:29.323 に答える
0

enable_ifいいえ、暗黙の変換演算子と一緒に使用することはできません。適用できる型はありません。すべての共通機能をmatrix_baseテンプレート クラスに移動し、特殊化をテンプレート クラスから継承して、特別な機能を追加します。別の方法は、とにかくメソッドを実装し、その中に静的アサートを配置して、インスタンス化された場合にコンパイラ エラーを発生させることです。これにより、クラスの明示的なインスタンス化が妨げられることに注意してください。

于 2011-10-07T23:27:55.417 に答える