Online Book Reader

Home Category

Professional C__ - Marc Gregoire [348]

By Root 1147 0
that you’ve suffered through the syntax to declare the template, the rest is easy. Instead of using Container by itself in the code, you must specify Container as the container type you use. For example, the constructor now looks like this (you don’t repeat the default template template parameter argument in the template specification for the method definition):

template template > class Container>

Grid::Grid(size_t inWidth, size_t inHeight) :

mWidth(inWidth), mHeight(inHeight)

{

mCells = new Container[mWidth];

for (size_t i = 0; i < mWidth; i++) {

mCells[i].resize(mHeight);

}

}

Code snippet from GridTemplateContainer\GridTemplateTemplate.h

After implementing all the methods, you can use the template as follows:

Grid myGrid;

myGrid.setElementAt(1, 2, 3);

myGrid.getElementAt(1, 2);

Grid myGrid2(myGrid);

Code snippet from GridTemplateContainer\GridTemplateTemplateTest.cpp

This C++ syntax is a bit convoluted because it is trying to allow for maximum flexibility. Try not to bog down in the syntax here, and keep the main concept in mind: You can pass templates as parameters to other templates.

More about Non-Type Template Parameters

You might want to allow the user to specify an empty (not in the literal sense) element that is used to initialize each cell in the grid. Here is a perfectly reasonable approach to implement this goal:

template

class Grid

{

public:

Grid(size_t inWidth = kDefaultWidth,

size_t inHeight = kDefaultHeight);

Grid(const Grid& src);

virtual ~Grid();

Grid& operator=(const Grid& rhs);

// Omitted for brevity

protected:

void copyFrom(const Grid& src);

T** mCells;

size_t mWidth, mHeight;

};

Code snippet from GridEmpty\Grid.h

This definition is legal. You can use the type T from the first parameter as the type for the second parameter, and non-type parameters can be const just like function parameters. You can use this initial value for T to initialize each cell in the grid:

template

Grid::Grid(size_t inWidth, size_t inHeight) :

mWidth(inWidth), mHeight(inHeight)

{

mCells = new T* [mWidth];

for (size_t i = 0; i < mWidth; i++) {

mCells[i] = new T[mHeight];

for (size_t j = 0; j < mHeight; j++) {

mCells[i][j] = EMPTY;

}

}

}

Code snippet from GridEmpty\Grid.h

The other method definitions stay the same, except that you must add the second type parameter to the template lines, and all the instances of Grid become Grid. After making those changes, you can then instantiate an int Grid with an initial value for all the elements:

Grid myIntGrid;

Grid myIntGrid2;

Code snippet from GridEmpty\GridTest.cpp

The initial value can be any integer you want. However, suppose that you try to create a SpreasheetCell Grid:

SpreadsheetCell emptyCell;

Grid mySpreadsheet; // WILL NOT COMPILE

Code snippet from GridEmpty\GridTest.cpp

That line leads to a compiler error because you cannot pass objects as arguments to non-type parameters.

Non-type parameters cannot be objects, or even doubles or floats. They are restricted to integral types, enums, pointers, and references.

This example illustrates one of the vagaries of template classes: They can work correctly on one type but fail to compile for another type.

Reference and Pointer Non-Type Template Parameters

A more comprehensive way of allowing the user to specify an initial empty element for the grid uses a reference to a T as the non-type template parameter. Here is the new class definition:

template

class Grid

{

// Everything else is the same as the previous example, except the

// template lines in the method definitions specify const T& EMPTY

// instead of const T EMPTY.

};

Code snippet from GridEmpty\GridRefNonType.h

Now you can instantiate this template class for any type. However, the reference you pass

Return Main Page Previous Page Next Page

®Online Book Reader