Время от времени при работе с шаблонами возникает необходимость специализировать шаблон класса по одному из аргументов. В качестве примера можно рассмотреть шаблон классов матриц, параметризованный типом элемента и размерами матрицы.
>template‹class T, int Rows, int Columns›
>class Matrix {
> //…
>};
Предположим, в процессе разработки выяснилось, что производительность программы неудовлетворительна, и узким местом является функция умножения матриц с элементами типа float, и что эту проблему можно решить путем использования intrinsic-функций процессора. При наличии соответствующей поддержки компилятора это легко можно сделать при помощи так называемой частичной специализации шаблонов классов:
>template‹int Rows, int Columns›
>class Matrix‹float, Rows, Columns› {
> //…
>};
Однако некоторые компиляторы не поддерживают частичную специализацию, и, как следствие, «не понимают» подобные конструкции. Желание получить эквивалентную функциональность при работе с такими компиляторами приводит к технике, описанной ниже.
Естественным первым шагом будет вынести различающуюся функциональность Matrix‹› в два базовых класса: Matrix_‹›, реализующий общий случай, и Matrix_float_‹› для специфики Matrix‹float,…›.
>template‹class T, int Rows, int Columns›
>class Matrix_ {
> //…
>};
>template‹int Rows, int Columns› class Matrix_float_ {
> //…
>};
Таким образом, проблема сведется к тому, чтобы класс Matrix‹T, Rows, Columns› наследовался от Matrix_‹T, Rows, Columns› или Matrix_float_‹Rows, Columns›, в зависимости от того, является ли параметр T шаблона Matrix‹› типом float. Решение этой задачи и является главным «фокусом» данной техники.
Несмотря на отсутствие поддержки частичной специализации, компилятор позволяет специализировать шаблоны полностью. Этот факт можно использовать для построения вложенных шаблонов с полной специализацией и выбором подходящего базового класса на соответствующем уровне вложенности.
>template‹class T›
>struct MatrixTraits {
> template‹int Rows, int Columns›
> struct Dimensions {
> typedef Matrix_‹T, Rows, Columns› Base;
> };
>};
>template‹›
>struct MatrixTraits‹float› {
> template‹int Rows, int Columns›
> struct Dimensions {
> typedef Matrix_float_‹Rows, Columns› Base;
> };
>};
Теперь осталось просто унаследовать Matrix‹› от соответствующего класса MatrixTraits‹›::…::Base.
>template‹class T, int Rows, int Columns›
>class Matrix: public MatrixTraits‹T›::template Dimensions‹Rows, Columns›::Base {
> //…
>};
ПРИМЕЧАНИЕ Согласно текущей версии стандарта, использование ключевого слова template при квалификации вложенного шаблона Dimensions в данном случае обязательно, хотя некоторые компиляторы и позволяют его опускать.