1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
Class template em(partial specializations) can be defined for any (subset)
hi(class template: partial specialization)
of template parameters. They can be defined for template type parameters
and for template non-type parameters alike. Our first partial specialization
defines a row of a generic tt(Matrix), mainly (but not only) used for the
construction of column marginals. Here is how such a partial specialization is
designed:
itemization(
it() The partial specialization starts with a template header defining all
template parameters that are em(not) specialized in the partial
specialization. This template header cannot specify any defaults (like
tt(DataType = double)) since defaults were already specified by the generic
class template definition. The specialization em(must) follow the definition
of the generic class template's definition, or the compiler complains that it
doesn't know what class is being specialized. Following the template header,
the class's interface starts. It's a class template (partial) specialization
so the class name must be followed by a template argument list specifying the
template arguments used by the partial specialization. The arguments specify
explicit types or values for some of the template's parameters. Remaining
types are simply copied from the class template partial specialization's
template parameter list. E.g., the tt(MatrixRow) specialization specifies 1
for the generic class template's tt(Rows) non-type parameter (as we're talking
here about a single row). Both tt(Columns) and tt(DataType) remain to be
specified. The tt(MatrixRow) partial specialization therefore starts as
follows:
verbinclude(//MATRIXROW examples/matrix.h)
it() A tt(MatrixRow) holds the data of a single row. So it needs a
data member storing tt(Columns) values of type tt(DataType). Since tt(Columns)
is a constant value, the tt(d_row) data member can be defined as an array:
verbinclude(//ROWDATA examples/matrix.h)
it() The class template partial specialization's constructors require some
attention. The default constructor is simple. It merely initializes the
tt(MatrixRow)'s data elements using tt(DataType)'s default constructor:
verbinclude(//ROWCONS1 examples/matrix.h)
Another constructor is needed initializing a tt(MatrixRow) object
with the column marginals of a generic tt(Matrix) object. This requires us to
provide the constructor with a non-specialized tt(Matrix) parameter.
The i(rule of thumb) here is to define a member template that allows us to
keep the general nature of the parameter. The generic tt(Matrix)
template requires three template parameters. Two of these were already
provided by the template specialization. The third parameter is mentioned in
the member template's template header. Since this parameter refers to the
number of rows of the generic matrix it is simply called tt(Rows).
Here then is the implementation of the second constructor, initializing the
tt(MatrixRow)'s data with the column marginals of a generic tt(Matrix) object:
verbinclude(//ROWCONS2 examples/matrix.h)
The constructor's parameter is a reference to a tt(Matrix) template using
the additional tt(Row) template parameter as well as the template parameters
of the partial specialization.
it() We don't really require additional members to satisfy our current
needs. To access the data elements of the tt(MatrixRow) an overloaded
tt(operator[]()) is of course useful. Again, the tt(const) variant can be
implemented like the non-tt(const) variant. Here is its implementation:
verbinclude(//ROWOPERATORINDEX examples/matrix.h)
)
Now that we have defined the generic tt(Matrix) class and the
partial specialization defining a single row the compiler selects the
row's specialization whenever a tt(Matrix) is defined using tt(Row = 1). For
example:
verb( Matrix<4, 6> matrix; // generic Matrix template is used
Matrix<1, 6> row; // partial specialization is used)
|