Implementing a Constant-Sized Matrix

Problem

You want an efficient matrix implementation where the dimensions (i.e., number of rows and columns) are constants known at compile time.

Solution

When the dimensions of a matrix are known at compile time, the compiler can more easily optimize an implementation that accepts the row and columns as template parameters as shown in Example 11-30.

Example 11-30. kmatrix.hpp

#ifndef KMATRIX_HPP
#define KMATRIX_HPP

#include "kvector.hpp"
#include "kstride_iter.hpp"

template
class kmatrix
{
public:
 // public typedefs
 typedef Value_T value_type;
 typedef kmatrix self;
 typedef Value_T* iterator;
 typedef const Value_T* const_iterator;
 typedef kstride_iter row_type;
 typedef kstride_iter col_type;
 typedef kstride_iter const_row_type;
 typedef kstride_iter const_col_type;

 // public constants
 static const int nRows = Rows_N;
 static const int nCols = Cols_N;

 // constructors
 kmatrix( ) { m = Value_T( ); }
 kmatrix(const self& x) { m = x.m; }
 explicit kmatrix(Value_T& x) { m = x.m; }

 // public functions
 static int rows( ) { return Rows_N; }
 static int cols( ) { return Cols_N; }
 row_type row(int n) { return row_type(begin( ) + (n * Cols_N)); }
 col_type col(int n) { return col_type(begin( ) + n); }
 const_row_type row(int n) const {
 return const_row_type(begin( ) + (n * Cols_N));
 }
 const_col_type col(int n) const {
 return const_col_type(begin( ) + n);
 }
 iterator begin( ) { return m.begin( ); }
 iterator end( ) { return m.begin( ) + size( ); }
 const_iterator begin( ) const { return m; }
 const_iterator end( ) const { return m + size( ); }
 static int size( ) { return Rows_N * Cols_N; }

 // operators
 row_type operator[](int n) { return row(n); }
 const_row_type operator[](int n) const { return row(n); }

 // assignment operations
 self& operator=(const self& x) { m = x.m; return *this; }
 self& operator=(value_type x) { m = x; return *this; }
 self& operator+=(const self& x) { m += x.m; return *this; }
 self& operator-=(const self& x) { m -= x.m; return *this; }
 self& operator+=(value_type x) { m += x; return *this; }
 self& operator-=(value_type x) { m -= x; return *this; }
 self& operator*=(value_type x) { m *= x; return *this; }
 self& operator/=(value_type x) { m /= x; return *this; }
 self operator-( ) { return self(-m); }

 // friends
 friend self operator+(self x, const self& y) { return x += y; }
 friend self operator-(self x, const self& y) { return x -= y; }
 friend self operator+(self x, value_type y) { return x += y; }
 friend self operator-(self x, value_type y) { return x -= y; }
 friend self operator*(self x, value_type y) { return x *= y; }
 friend self operator/(self x, value_type y) { return x /= y; }
 friend bool operator==(const self& x, const self& y) { return x != y; }
 friend bool operator!=(const self& x, const self& y) { return x.m != y.m; }
private:
 kvector m;
};

#endif

Example 11-31 shows a program that demonstrates how to use the kmatrix template class.

Example 11-31. Using kmatrix

#include "kmatrix.hpp"

#include 

using namespace std;

template
void outputRowOrColumn(Iter_T iter, int n) {
 for (int i=0; i < n; ++i) {
 cout << iter[i] << " ";
 }
 cout << endl;
}

template
void initializeMatrix(Matrix_T& m) {
 int k = 0;
 for (int i=0; i < m.rows( ); ++i) {
 for (int j=0; j < m.cols( ); ++j) {
 m[i][j] = k++;
 }
 }
}

template
void outputMatrix(Matrix_T& m) {
 for (int i=0; i < m.rows( ); ++i) {
 cout << "Row " << i << " = ";
 outputRowOrColumn(m.row(i), m.cols( ));
 }
 for (int i=0; i < m.cols( ); ++i) {
 cout << "Column " << i << " = ";
 outputRowOrColumn(m.col(i), m.rows( ));
 }
}

int main( )
{
 kmatrix m;
 initializeMatrix(m);
 m *= 2;
 outputMatrix(m);
}

The program in Example 11-31 produces the following output:

Row 0 = 0 2 4 6
Row 1 = 8 10 12 14
Column 0 = 0 8
Column 1 = 2 10
Column 2 = 4 12
Column 3 = 6 14

 

Discussion

This design and usage for the kmatrix class template in Example 11-30 and Example 11-31 is very similar to the matrix class template presented in Recipe 11.14. The only significant difference is that to declare an instance of a kmatrix you pass the dimensions as template parameters, as follows:

kmatrix m; // declares a matrix with five rows and six columns

It is common for many kinds of applications requiring matricies that the dimensions are known at compile-time. Passing the row and column size as template parameters enables the compiler to more easily apply common optimizations such as loop-unrolling, function inlining, and faster indexing.

Like the constant-sized vector template presented earlier (kvector), the kmatrix template is particularly effective when using small matrix sizes.

 

See Also

Recipe 11.14 and Recipe 11.16

Building C++ Applications

Code Organization

Numbers

Strings and Text

Dates and Times

Managing Data with Containers

Algorithms

Classes

Exceptions and Safety

Streams and Files

Science and Mathematics

Multithreading

Internationalization

XML

Miscellaneous

Index

show all menu



C++ Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2006
Pages: 241
Similar book on Amazon

Flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net