class DiabolicalData
{
    public :
          //
        //    Enums
        //
        enum TestFlag
        {
            e1        = 0x1,               //    Bit flags representing the members and their types.
            e2        = 0x2,               //    Here's the checklist to add a new member to this class:
            e3        = 0x4,               //    1) Add a value to this enum to represent the member
            e4        = 0x8,               //    2) Add the member's type to the TestTypes below
            e5        = 0x10,              //    3) Add the member to this class normally
                                           //    4) Add access code for this member in the GetArrayPtr method.
            //    No constants after here...
            eLast    = e5,                 //    Note : I've used bit flags here but normal incrementing enum values
                                           //    are possible too; just change the Unroll<TestFlag(i << 1)::???
                                           //    call in the Unroll static methods to Unroll<TestFlag(i + 1)::???
        };
          //
        //    Structs
        //
        //    Member types accessible by TestFlag value
        template <TestFlag i struct TestType    {                                           };
        struct TestType<e1                        { typedef char VType;                     };
        struct TestType<e2                        { typedef int VType;                      };
        struct TestType<e3                        { typedef float VType;                    };
        struct TestType<e4                        { typedef char * VType;                   };
        struct TestType<e5                        { typedef struct { int x,y,z; } VType;    };
  
    private :
          struct DiabolicalUnroller    //    Keep all the Unroll structs in here so they are publically accessible to
                                     //    each other (but we keep the mechanism as a whole private).
        {
            template <TestFlag i struct Unroll
            {
                //
                //    Typedefs
                //
                typedef TestType<i::VType UnrollType;    //    Type associated with the array matched to this flag
                  //
                //    Static Functions
                //
                static __forceinline void _Clear(DiabolicalData * pData)
                {
                    //    Sets the flagged array to point to null
                    UnrollType * * pArray = (UnrollType * *)pData-GetArrayPtr(i);
                      if (pArray)
                    {
                        *pArray = 0;
                    }
                    else
                    {
                        printf("Unroll::_Clear - Array flag %d is unsupported by GetArrayPtr\n",i);
                    }
                      Unroll<TestFlag(i << 1)::_Clear(pData);
                }
                  static __forceinline void _Allocate(DiabolicalData * pData,const int Num)
                {
                    //    Allocates Num entries to the flagged array
                    UnrollType * * pArray = (UnrollType * *)pData-GetArrayPtr(i);
                      if (pArray)
                    {
                        if (*pArray)
                        {
                            delete [](*pArray);
                        }
                        *pArray = new UnrollType[Num];
                    }
                    else
                    {
                        printf("Unroll::_Allocate - Array flag %d is unsupported by GetArrayPtr\n",i);
                    }
                      Unroll<TestFlag(i << 1)::_Allocate(pData,Num);
                }
                  static __forceinline void _AllocateMarked(DiabolicalData * pData,const int Num,const int Mark)
                {
                    //    Allocates Num entries to the flagged array if i is flagged in Mark
                    UnrollType * * pArray = (UnrollType * *)pData-GetArrayPtr(i);
                      if (pArray && ((Mark & i) != 0))
                    {
                        if (*pArray)
                        {
                            delete [](*pArray);
                        }
                        *pArray = new UnrollType[Num];
                    }
                    else
                    {
                        printf("Unroll::_AllocateMarked - Array flag %d is unsupported by GetArrayPtr\n",i);
                    }
                      Unroll<TestFlag(i << 1)::_AllocateMarked(pData,Num,Mark);
                }
                  static __forceinline void _Deallocate(DiabolicalData * pData)
                {
                    //    Deallocates the flagged array
                    UnrollType * * pArray = (UnrollType * *)pData-GetArrayPtr(i);
                      if (pArray)
                    {
                        delete [](*pArray);
                        *pArray = 0;
                    }
                    else
                    {
                        printf("Unroll::_Deallocate - Array flag %d is unsupported by GetArrayPtr\n",i);
                    }
                      Unroll<TestFlag(i << 1)::_Deallocate(pData);
                }
            };
              struct Unroll<TestFlag(eLast << 1)
            {
                //    Empty unroll struct - terminates the loop unroll
                static __forceinline void _Clear(DiabolicalData*)                                { }
                static __forceinline void _Allocate(DiabolicalData*,const int)                    { }
                static __forceinline void _AllocateMarked(DiabolicalData*,const int,const int)    { }
                static __forceinline void _Deallocate(DiabolicalData*)                            { }
            };
          };
          //
        //    Members
        //
        TestType<e1::VType *    m_pData1;        //    Bogus data
        TestType<e2::VType *    m_pData2;        //    arrays to
        TestType<e3::VType *    m_pData3;        //    test this
        TestType<e4::VType *    m_pData4;        //    disgusting
        TestType<e5::VType *    m_pData5;        //    code
      public :
          //
        //    Methods
        //
        DiabolicalData()
        {
            DiabolicalUnroller::Unroll<e1::_Clear(this);
        }
          void * * GetArrayPtr(TestFlag F)
        {
            //    Array get method - update here when adding new array members
            switch (F)
            {
                case e1 :    return (void * *)(&m_pData1);
                case e2 :    return (void * *)(&m_pData2);
                case e3 :    return (void * *)(&m_pData3);
                case e4 :    return (void * *)(&m_pData4);
                case e5 :    return (void * *)(&m_pData5);
            };
              return 0;
        }
          //
        //    Test Functions
        //
        void AllocateAll(const int NumToAllocate)
        {
            //    Allocates NumToAllocate entries to each of the arrays
            DiabolicalUnroller::Unroll<e1::_Allocate(this,NumToAllocate);
        }
          void AllocateMarked(const int NumToAllocate,const int Mark)
        {
            //    Allocates NumToAllocate entries to each of the marked arrays
            DiabolicalUnroller::Unroll<e1::_AllocateMarked(this,NumToAllocate,Mark);
        }
          void DeallocateAll()
        {
            //    Deallocates all the arrays
            DiabolicalUnroller::Unroll<e1::_Deallocate(this);
        }
  };  |