Professional C__ - Marc Gregoire [354]
virtual ~NDGrid();
NDGrid void resize(size_t newSize); T& operator[](size_t x); const T& operator[](size_t x) const; size_t getSize() const { return mSize; } static const size_t kDefaultSize = 10; protected: void copyFrom(const NDGrid T* mElems; size_t mSize; }; Code snippet from NDGrid\NDGrid.h Here the recursion ends: The element type is T, not another template instantiation. The trickiest aspect of the implementations, other than the template recursion itself, is appropriately sizing each dimension of the array. This implementation creates the N-dimensional array with every dimension of equal size. It’s significantly more difficult to specify a separate size for each dimension. However, even with this simplification, there is still a problem: The user should have the ability to create the array with a specified size, such as 20 or 50. Thus, one constructor takes an integer size parameter. However, when you dynamically allocate the nested array of grids, you cannot pass this size value on to the grids because arrays create objects using their default constructor. Thus, you must explicitly call resize() on each grid element of the array. That code follows, with the default and one-argument constructors separated for clarity. The base case doesn’t need to resize its elements because the elements are Ts, not grids. Here are the implementations of the main NDGrid template, with highlights showing the differences from the OneDGrid: template NDGrid { mElems = new NDGrid // Allocating the array above calls the 0-argument // constructor for the NDGrid // it with the default size. Thus, we must explicitly call // resize() on each of the elements. for (size_t i = 0; i < mSize; i++) { mElems[i].resize(inSize); } } template NDGrid { mElems = new NDGrid } template NDGrid { copyFrom(src); } template NDGrid { delete [] mElems; mElems = nullptr; } template void NDGrid { mSize = src.mSize; mElems = new NDGrid for (size_t i = 0; i < mSize; i++) { mElems[i] = src.mElems[i]; } } template NDGrid { // 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 NDGrid { // Allocate the new array with the new size. NDGrid // Copy all the elements, handling the cases where newSize is // larger than mSize and smaller than mSize. for (size_t i = 0; i < newSize && i < mSize; i++) { newElems[i] = mElems[i]; // Resize the nested Grid elements recursively. newElems[i].resize(newSize); } // Store the new size and pointer to the new array. // Free the memory for the old array first. mSize = newSize; delete [] mElems; mElems = newElems; } template NDGrid { return mElems[x]; } template const NDGrid { return mElems[x]; } Code snippet from NDGrid\NDGrid.h Here are the implementations of the partial specialization (base case). Note that you must rewrite a lot of the code because you don’t inherit any implementations with specializations. Highlights show the differences from the non-specialized NDGrid: template NDGrid { mElems = new T[mSize]; } template NDGrid