Listing 9: Specifying dimensions

// Class that encapsulates a const unsigned int (&)[N]
template <unsigned int N>
class ArraySize
{
   typedef const unsigned int (&UIntArrayN)[N];

   unsigned int m_Dimensions[N];

   ArraySize(const unsigned int (&Dimensions)[N-1],
             unsigned int dim)
   {
      std::copy(&Dimensions[0],&Dimensions[N-1],m_Dimensions);
      m_Dimensions[N-1]=dim;
   }

public:

   ArraySize<N+1> operator () (unsigned int dim) 
   { 
      return ArraySize<N+1>(m_Dimensions,dim);
   }

   operator UIntArrayN () const { return m_Dimensions; }

   friend class ArraySizes;
   friend class ArraySize<N-1>;
};

// Starting point to build a const unsigned int (&)[N] on the fly
class ArraySizes
{
   unsigned int m_Dimensions[1];   

public:
      
   explicit ArraySizes(unsigned int dim) 
   { 
      m_Dimensions[0]=dim;
   }

   ArraySize<2> operator () (unsigned int dim) 
   { 
      return ArraySize<2>(m_Dimensions,dim);
   }
};

// Using ArraySize to specify Array dimensions type-safely
int main()
{
   Array<double, 3> A3(ArraySizes(10)(20)(30)); // OK
   //...
   A3.resize(ArraySizes(30)(40)(50));           // OK

   A3.resize(ArraySizes(10)(20));         // COMPILE-TIME ERROR!
   A3.resize(ArraySizes(10)(20)(30)(40)); // COMPILE-TIME ERROR!

   return 0;
}