Специализировать шаблон структуры с шаблоном класса в качестве параметра - PullRequest
3 голосов
/ 05 июня 2011

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

template< typename TDataType, size_t rows, size_t cols > class MyMatrix

Матрицы могут быть вложенными, поэтому TDataType может быть целочисленным типом, но также MyMatrix<...> сам по себе, что приводит к тому, что тип данных для транспонированной матрицы не обязательно совпадает с типом исходной матрицы, например:Transpose( MyMatrix< MyMatrix< char, 2, 3 >, 4, 6 > ) ==> MyMatrix< MyMatrix< char, 3, 2 >, 6, 4 > (тип данных внешней матрицы изменился)

Моя первая попытка выведения транспонированного типа была:

template< typename TDataType >
struct Transpose
  {
  typedef TDataType type;
  };

template<>
struct Transpose< MyMatrix<TDataType, rows, cols> >
  {
  typedef MyMatrix<typename Transpose<TDataType>::type, cols, rows> type;
  };

Я не нашел способа сделать это, потому что я могуКажется, что не специализируется Transpose-шаблон с MyMatrix (неизвестные TDataType и подобные ошибки).

Единственное компилируемое решение, которое я придумал (я даже не знаю, работает ли оно еще), это:

template< typename TMatrixType, typename TDataType, size_t rows, size_t cols >
struct Transpose
  {
  typedef TMatrixType type;
  };

template< typename TDataType, size_t rows, size_t cols >
struct Transpose< MyMatrix<TDataType, rows, cols>, TDataType, rows, cols >
  {
  typedef MyMatrix< typename Transpose<TDataType,TDataType,rows,cols>::type, cols, rows > type;
  };

Мне кажется, я слишком усложняю вещи;Есть ли более простое решение для достижения того, чего я хочу?


Ответ на ответы на мой вопрос (я разместил вопрос без учетной записи, поэтому у меня недостаточно представителей, чтобы делать обычные вещи)путь).Большое спасибо!

@ Bo Persson @Will A: Я не собираюсь использовать это как матричную библиотеку общего назначения, я хочу выполнять операции с матрицами определенного (заранее известного) размера и хочу видетьгде я могу получить с помощью этого подхода.Это может позволить мне оптимизировать макет памяти для матриц (например, выровнять векторы строк на 32-байтовых границах) и делать другие интересные вещи.Я ожидаю, что буду делать это очень много раз, но главное, что я пытаюсь получить - это опыт и выяснение того, что работает, а что нет (и что трудно сделать, а что нет.'t).

@ Бо Перрсон: Я знаю, почему первая версия не компилируется, но мне было интересно, была ли более простая версия моей второй попытки, которая могла бы работать.Основная проблема заключается в том, что MyMatrix сам является шаблоном класса, и мне нужно каким-то образом передать его аргументы в Transpose-struct.

@ VJo: Не думаю, что это сработает.Если T сам MyMatrix <..>, то матрица транспонирования должна иметь Transpose<T> в качестве типа данных, а не сам T.Для всех основных типов (char, int, double ...) это, конечно, правильно и намного проще.

Ответы [ 4 ]

3 голосов
/ 05 июня 2011

Да, вы усложняете.

Если у вас есть такое объявление:

template< typename TDataType, size_t rows, size_t cols > class MyMatrix

, тогда функция транспонирования должна выглядеть так:

template< typename T, size_t rows, size_t cols >
MyMatrix< T, cols, rows > Transpose( const MyMatrix< T, rows, cols > & m )
{
  MyMatrix< T, cols, rows > res;
  // implementation
  return res;
}
0 голосов
/ 06 июня 2011

Я бы написал это примерно так, чтобы разрешить произвольную глубину рекурсии (матрицы матриц матриц ...)

template<typename T, unsigned rows, unsigned cols>
struct MyMatrix
{
  typedef T value_type;
  T stuff[rows][cols];  // or whatever                                      
};

// For basic types, transpose is identity.                                  
template<typename T>
struct Transpose {
  typedef T result_type;
  result_type operator()(const T & in) {
    return in;
  }
};

// For more complex types, specialize and invoke recursively.
template<typename T, unsigned rows, unsigned cols>
struct Transpose<MyMatrix<T, rows, cols> > {
  typedef MyMatrix<Transpose<T>, cols, rows> result_type;
  result_type operator()(const MyMatrix<T, rows, cols> & in) {
    Transpose<T> transposer;
    // (invoke transposer on each element of in and build result)           
  }
};

Здесь Transpose является функтором; вы создаете его экземпляр, но вызываете его как функцию. Для дополнительного кредита, вы можете получить его от unary_function и получить result_type typedef бесплатно ...

0 голосов
/ 05 июня 2011

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

Вторая версия верна в зависимости от языка, но, как говорит Уилл А, действительно ли вы хотите, чтобы каждая комбинация строки и столбца создала новый тип?

0 голосов
/ 05 июня 2011

Что вы получаете от включения строк / столбцов в определение шаблона?

По моему личному мнению, это слишком усложняет ситуацию.Во что бы то ни стало, включите тип данных в шаблон, но указание размеров кажется неправильным.

...