2016-06-15 4 views
0

Я создаю простой класс C++ шаблона матрицы, со следующим определением:C++ шаблона матрица класс - квадратная матрица специализация

template<uint n, uint m, typename T = double> 
class Matrix { 
private: 
    T data[n][m]; 

    static Matrix<n, m, T> I; 

public: 
    Matrix(); 
    Matrix(std::initializer_list<T> l); 

    T& at(uint i, uint j); // one-based index 
    T& at_(uint i, uint j); // zero-based index 

    template<uint k> Matrix<n, k, T> operator*(Matrix<m, k, T>& rhs); 
    Matrix<m, n, T> transpose(); 
    Matrix<n, m, T> operator+(const Matrix<n, m, T>& rhs); 
    Matrix<n, m, T>& operator+=(const Matrix<n, m, T>& rhs); 
    Matrix<n, m, T> operator-(const Matrix<n, m, T>& rhs); 
    Matrix<n, m, T>& operator-=(const Matrix<n, m, T>& rhs); 
    Matrix<n, m, T> operator*(const T& rhs); 
    Matrix<n, m, T>& operator*=(const T& rhs); 
    Matrix<n, m, T> operator/(const T& rhs); 
    Matrix<n, m, T>& operator/=(const T& rhs); 

    static Matrix<n, m, T> identity(); 
}; 

(uint определяются как unsigned int)

Окончательные функция Matrix<n, m, T> identity() стремится вернуть статический элемент I, который является идентификационной матрицей, используя базовый одноэлементный шаблон. Очевидно, что матрица определена только для квадратных матриц, поэтому я попытался это:

template<uint n, typename T> 
inline Matrix<n, n, T> Matrix<n, n, T>::identity() { 
    if (!I) { 
     I = Matrix<n, n, T>(); 
     for (uint i = 0; i < n; ++i) { 
      I.at(i, i) = 1; 
     } 
    } 
    return I; 
} 

который дает ошибку C2244 'Matrix<n,n,T>::identity': unable to match function definition to an existing declaration.

Мое впечатление, что я мог бы сделать какую-то специализацию шаблона, где количество столбцов и строк равно. Я не уверен, что это возможно, но ваша помощь будет высоко оценена.

ответ

1

Попробуйте это:

static Matrix<n, m> identity() { 
    static_assert(n == m, "Only square matrices have a identity"); 
    return {}; //TODO 
} 

См: http://cpp.sh/7te2z

+0

Это не сработает. Создание экземпляра 'Matrix' с n! = M приведет к созданию экземпляра функции, которая плохо сформирована при n! = M. Вы должны быть немного более тонким. – Brian

+0

@Brian, вы правы, он не компилируется. Я не понимаю, почему SFINAE не использует и не игнорирует функцию. Во всяком случае, отредактированный мой ответ, static_assert, похоже, работает и даже дает лучшее сообщение об ошибке – tkausl

+0

SFINAE возникает только при сбое замены при выводе аргумента шаблона. – Brian

0

Partial specialization класса шаблона допускается для всего класса, но не для его одного члена.

Члены частичной специализации не относятся к элементам первичного шаблона .

Именно по этой причине ваша ошибка компиляции.

Конечно, специализация всего шаблона матрицы для квадратного матричного футляра не имеет смысла. @tkausl уже ответил, как сделать функцию identity() доступной только для квадратных матричных типов.

Однако, я хотел бы обратить ваше внимание в сторону на пару вопросов в вашей реализации Matrix:

  1. Данные матрицы представляет собой обычный массив (вместо динамически распределяемой массив или std::vector). Это имеет следующие недостатки:

    • sizeof(Matrix<N, M, T>) == sizeof(T)*N*M. Выделение больших матриц в стеке может привести к stack overflow.
    • Невозможность использования семантики перемещения (поскольку данные неотделимы от матричного объекта).

    Хотя, если размеры матрицы фиксированы во временных константах компиляции, то, скорее всего, они будут небольшими числами. Если это так, то оплата стоимости динамического распределения действительно может быть необоснованной.

  2. identity() возвращает свой результат по значению (а не по постоянной ссылке).

  3. I (идентификационная матрица) является статическим членом класса. Лучше сделать его статической переменной внутри функции identity().

Смежные вопросы