Professional C__ - Marc Gregoire [353]
template
OneDGrid { delete [] mElems; mElems = nullptr; } template void OneDGrid { mSize = src.mSize; mElems = new T[mSize]; for (size_t i = 0; i < mSize; i++) { mElems[i] = src.mElems[i]; } } template OneDGrid { // Check for self-assignment. if (this == &rhs) { return *this; } // Free the old memory. delete [] mElems; mElems = nullptr; // Copy the new memory. copyFrom(rhs); return *this; } template void OneDGrid { T* newElems = new T[newSize]; // Allocate the new array of the new size // Handle the new size being smaller or bigger than the old size. for (size_t i = 0; i < newSize && i < mSize; i++) { // Copy the elements from the old array to the new one. newElems[i] = mElems[i]; } mSize = newSize; // Store the new size. delete [] mElems; // Free the memory for the old array. mElems = newElems; // Store the pointer to the new array. } template T& OneDGrid { return mElems[x]; } template const T& OneDGrid { return mElems[x]; } Code snippet from OneDGrid\OneDGrid.h With this implementation of the OneDGrid, you can create multidimensional grids like this: OneDGrid OneDGrid OneDGrid singleDGrid[3] = 5; twoDGrid[3][3] = 5; threeDGrid[3][3][3] = 5; Code snippet from OneDGrid\OneDGridTest.cpp This code works fine, but the declarations are messy. We can do better. A Real N-Dimensional Grid You can use template recursion to write a “real” N-dimensional grid because dimensionality of grids is essentially recursive. You can see that in this declaration: OneDGrid You can think of each nesting OneDGrid as a recursive step, with the OneDGrid of int as the base case. In other words, a three-dimensional grid is a single-dimensional grid of single-dimensional grids of single-dimensional grids of ints. Instead of requiring the user to do this recursion, you can write a template class that does it for you. Then, you can create N-dimensional grids like this: NDGrid NDGrid NDGrid The NDGrid template class takes a type for its element and an integer specifying its “dimensionality.” The key insight here is that the element type of the NDGrid is not the element type specified in the template parameter list, but is in fact another NDGrid of dimensionality one less than the current. In other words, a three-dimensional grid is an array of two-dimensional grids; the two-dimensional grids are each arrays of one-dimensional grids. With recursion, you need a base case. You can write a partial specialization of the NDGrid for dimensionality of 1, in which the element type is not another NDGrid, but is in fact the element type specified by the template parameter. Here is the general NDGrid template definition, with highlights showing where it differs from the OneDGrid shown in the previous section: template class NDGrid { public: NDGrid(); NDGrid(size_t inSize); NDGrid(const NDGrid virtual ~NDGrid(); NDGrid void resize(size_t newSize); NDGrid const NDGrid size_t getSize() const { return mSize; } static const size_t kDefaultSize = 10; protected: void copyFrom(const NDGrid NDGrid size_t mSize; }; Code snippet from NDGrid\NDGrid.h Note that mElems is a pointer to an NDGrid Here is the template definition for the base case: template class NDGrid { public: NDGrid(size_t inSize = kDefaultSize); NDGrid(const