Listing 5: Implementation of indexing process

template <typename T, unsigned int N>
class SubArray
{
   const size_type * const m_pNDimensions;
   const size_type * const m_pSubArrayLen;

   T * const m_pElements; // The elements

   SubArray<T, N>(T * pElements, const size_type * pNDimensions, 
                  const size_type * pSubArrayLen)
     : m_pElements(pElements), m_pNDimensions(pNDimensions),
       m_pSubArrayLen(pSubArrayLen){} 

public:

   SubArray<T, N-1> operator [](size_type Index)
   {
      assert(Index<m_pNDimensions[0]);
      return
         SubArray<T, N-1>(&m_pElements[Index*m_pSubArrayLen[0]],
                          m_pNDimensions+1, m_pSubArrayLen+1);
   }

   const SubArray<T, N-1>
   operator [](size_type Index) const
   {
      assert(Index<m_pNDimensions[0]);
      return
         SubArray<T, N-1>(&m_pElements[Index*m_pSubArrayLen[0]],
                          m_pNDimensions+1, m_pSubArrayLen+1);
   }

   friend class Array<T, N+1>; 
   friend class SubArray<T, N+1>; 
};

template <typename T>
class SubArray<T, 1>
{
   const size_type * const m_pNDimensions;

   T * const m_pElements; // The elements

   SubArray<T, 1>(T * pElements, const size_type * pNDimensions,
                  const size_type * pSubArrayLen)
      : m_pElements(pElements), m_pNDimensions(pNDimensions){}

public:

   T & operator [] (size_type  Index)
   {
      assert(Index<m_pNDimensions[0]);
      return m_pElements[Index];
   }

   const T & operator [] (size_type Index) const
   {
      assert(Index<m_pNDimensions[0]);
      return m_pElements[Index];
   }

   friend class Array<T, 2>;
   friend class SubArray<T, 2>; 
};

template <typename T, unsigned int N>
class Array
{
   T  *       m_pArrayElements; // Points to all
                                // the actual elements
   size_type  m_nArrayElements; // Total number of array elements

   size_type  m_NDimensions[N]; // Sizes of the N dimensions
   size_type  m_SubArrayLen[N]; // Dimensions of subarrays

public:
 
   Array<T, N>()
      : m_pArrayElements(NULL), m_nArrayElements(0)
   { /*...*/ }
  ~Array<T, N>() { delete [] m_pArrayElements; }
   
   SubArray<T, N-1> operator [] (size_type Index) 
   {
      assert(Index<m_NDimensions[0]);  
      return SubArray<T, N-1>
                (&m_pArrayElements[Index*m_SubArrayLen[0]],
                 m_NDimensions+1, m_SubArrayLen+1);
   }

   const SubArray<T, N-1>
   operator [] (size_type Index) const 
   {  
      assert(Index<m_NDimensions[0]);  
      return SubArray<T, N-1>
                (&m_pArrayElements[Index*m_SubArrayLen[0]],
                 m_NDimensions+1,m_SubArrayLen+1);
   }
};