Professional C__ - Marc Gregoire [349]
extern const int x = 0;
Note that this line occurs outside of any function or method body. Here is a program that declares int and SpreadsheetCell grids with initialization parameters:
extern const int emptyInt = 0;
extern const SpreadsheetCell emptyCell(0);
int main()
{
Grid Grid Grid return 0; } Code snippet from GridEmpty\GridTestRefNonType.cpp Reference and pointer template arguments must refer to global variables that are available from all translation units. The technical term for these types of variables is data with external linkage. Using Zero-Initialization of Template Types Neither of the options presented so far for providing an initial empty value for the cells is very attractive. Instead, you may simply want to initialize each cell to a reasonable default value that you choose (instead of allowing the user to specify). Of course, the immediate question is: What’s a reasonable value for any possible type? For objects, a reasonable value is an object created with the default constructor. In fact, that’s exactly what you’re already getting when you create an array of objects. However, for simple data types like integral types (int, short, ...), a reasonable initial value is 0; for floating point types, a reasonable initial value is 0.0; and for pointers, a reasonable initial value is nullptr. Therefore, what you really want to be able to do is assign this initial value to non-objects and use the default constructor on objects. You actually saw the syntax for this behavior in the section on “Method Templates with Non-Type Parameters” in the previous chapter. Here is the implementation of the Grid template constructor using the zero-initialization syntax: template Grid 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] = T(); } } } Code snippet from GridEmpty\GridZeroInitialized.h Given this ability, you can revert to the original Grid class (without an EMPTY non-type parameter) and just initialize each cell element to its zero-initialized “reasonable value.” TEMPLATE CLASS PARTIAL SPECIALIZATION template class Grid { public: void setElementAt(size_t x, size_t y, const T& inElem); T& getElementAt(size_t x, size_t y); const T& getElementAt(size_t x, size_t y) const; size_t getHeight() const { return HEIGHT; } size_t getWidth() const { return WIDTH; } protected: T mCells[WIDTH][HEIGHT]; }; Code snippet from GridPartialString\Grid.h You could specialize this template class for char* C-style strings like this: #include "Grid.h" // The file containing the Grid template definition template class Grid { public: Grid(); Grid(const Grid virtual ~Grid(); Grid const Grid void setElementAt(size_t x, size_t y, const char* inElem);
The char* class specialization shown in the previous chapter is called full template class specialization because it specializes the Grid template for every template parameter. There are no template parameters left in the specialization. That’s not the only way you can specialize a class; you can also write a partial class specialization, in which you specialize some template parameters but not others. For example, recall the basic version of the Grid template with width and height non-type parameters: