2011-06-05 3 views
3

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

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-байтных границах) и делать другие виды фанки. Я ожидаю, что застреваю себя в ногу очень много, делая это, но главное, что я пытаюсь получить здесь, это опыт и выяснить, что работает, а что нет (и что трудно сделать, а что нет «т).

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

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

ответ

0

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

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

+2

Вероятно, он думает, что компилятор может работать с открытым кодом на малых матрицах (и, таким образом, избегать накладных расходов цикла), когда границы константы компиляции. Возможно, он прав. – Nemo

+0

@Nemo - ах, ОК - C++ - это не мое дело (не более) - так мне показалось странным. Спасибо Немо. –

+1

В зависимости от вашего поля также может быть полезной дополнительная безопасность типов, а также возможность распределения кучи вашей базовой структуры данных без кучи. В конечном счете, более общее решение обычно является лучшим вызовом, но есть определенные аргументы в пользу уникальных типов. –

3

Да, вы затрудняетесь.

Если у вас есть заявление, как это:

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

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

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

0

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

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)   
    } 
}; 

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