Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Untyped classes in C++ without templates??

Options
  • 04-03-2003 6:33pm
    #1
    Closed Accounts Posts: 76 ✭✭


    Lo all,
    I've been called upon to port some heavily templatised framework classes implemented in C++ onto an older processor. Theres already a C++ compiler included in our build system (Microtec ccc68k) but it's template support is poor.. well, actually it has none.

    So I know I will have to either
    1) write new typed classes for each type that will use the generic class
    2) Make a union of all the types and make a single new framework class based on the union type with some kind of tag to identify which type is used in a particular object

    erm.. thats all i've thought of so far. So has anyone worked around this kind of compiler restriction before with some success?

    niall.


Comments

  • Closed Accounts Posts: 9,314 ✭✭✭Talliesin


    Another option is to build instances of the templated classes programatically.

    One evil way (indeed using an evil practice templates were supposed to make obsolete) would be to use macros, for example:

    original code:
    template<class T> void swap(T& x, T& y){
    	T tmp(x);
    	x = y;
    	y = tmp;
    }
    

    in this case a macro could replace "template<class T>" with an empty string and replace "T" with int, or whatever type you wanted.

    While this would be less convenient that cut-and-paste here, it would be useful with a large class.

    Then you can build bunches of classes as needed from redefining the macros in question, and repeatedly #including the template definitions.

    However a big problem with this is that you may have dependencies on the rule that a non-virtual member functionnot instantiated until it is first used. This won't happen with the macro method, and as well as increasing bloat it might create uncompilable code.

    Another solution therefore is to write something to generate the appropriate .h and .cpp files from the templates, and include them as needed. You can edit out anything uncompilable that is created, and generally have more control. However this comes at the cost of completely losing every advantage the templates gave you.

    Of course the other alternative is to get a better compiler (to think I moan about the one I'm using not having covariance...).


  • Closed Accounts Posts: 76 ✭✭photty


    Thanks for those ideas.. I'm kind of sold on the following approach:

    In this simple example we have a Bucket to hold data in. A BucketT inherits from a ReadWrite Bucket (set) which inherits from a ReadOnly Bucket(get). Base classes not shown..

    Original class:
      template<class T> class BucketT : public BucketRW<T>
      {
        public:
          // Constructor
          explicit BucketT(const T &initValue) : BucketRW<T>(), theData(initValue) {}
       
          // Get the contained data theData
           virtual void get(T &data) const                         
          {
             data = theData;
          }
    
          /// Set the contained data
          virtual void set(const T &data)     
          {
            theData = data; 
          }
    
         private:
          // Copy constructor
          explicit BucketT(const BucketT &bucket); // not implemented
          // Assignment overload operator
          BucketT &operator=(const BucketT &bucket);  // not implemented
    
        protected:
          T  theData;
      };
    


    Now the untemplatised version:
      class BucketT : public BucketRW
      {
        public:
    
          // Constructor
          // initValue: The initial value assigned to theData during construction
          explicit BucketT(unsigned char tag, void *initValue) : BucketRW() 
          { /* init the value using memcpy. use tag to get the size of the type */ }
            
          // Get the contained data theData
          // data: A reference to the place to copy theData
          virtual void get(unsigned char tag, void *data) const                         
          {
            /* get the value using using memcpy. use tag to get the size of the type! */
          }
    
          /// Set the contained data theData
          virtual void set(unsigned char tag, void *data)     
          {
            /* set the value using using memcpy. use tag to get the size of the type! */
          }
    
        private:
          // Copy constructor
          explicit BucketT(const BucketT &bucket); // not implemented
          // Assignment overload operator
          BucketT &operator=(const BucketT &bucket);  // not implemented
    
        protected:
          AllTypes  theData;
      };
    

    where AllTypes is something like:
    #define AllTypes_int_TAG                       0
    #define AllTypes_float_TAG                    1
    #define AllTypes_long_TAG                    2
    
    typedef union 
    {
      int           intType; 
      float         floatType;
      long          longType;
    } union_AllTypes_val;
    
    typedef struct {
      unsigned char              tag;
      union_AllTypes_val val;
    } AllTypes;
    

    So once i write some code to get the sizes of different types this kind of basic container should work... right?? Although every object would be using the largest type wasting memory. Bah my head hurts now.

    Any other ideas or improvements on the above?


  • Registered Users Posts: 2,281 ✭✭✭DeadBankClerk


    [php]

    #typedef AnyClass __StackItem

    class Stack
    {
    __StackItem* array;

    public void push (__StackItem* item);
    public __StackItem* pop (void);
    }

    [/php]

    When you want to use the Stack class typedef the class you want in the stack to __StackItem


  • Closed Accounts Posts: 76 ✭✭photty


    Nice idea but no cigar.. i tried it out and i don't think you can redefine __StackItem on the fly like that.
    typedef int __StackItem;
    
    class Stack
    {
        __StackItem _item;
    
      public:
        void set(__StackItem& item) { _item = item; };
        __StackItem get(void) { return _item; };
    };
    

    For example the following will not compile:
      long aLong = 1234;
      ...
      typedef long __StackItem;
      Stack myStack;
      myStack.set(aLong);
      ...
    

    I get the following error in microsoft:
    error C2664: 'set' : cannot convert parameter 1 from 'unsigned char' to 'int &'

    So it appears that the redefinition of __StackItem does not change the type of the class...


  • Closed Accounts Posts: 76 ✭✭photty


    So a while back we came up with a way to get around the lack of template support by raping the preprocessor. Thought i'd share it in case anyone gets lumped with a horrible porting job like i did! ;)
    /** The original template class */
    template<class T> class BucketT
    {
      public:
        explicit BucketT(const T &initValue) : theData(initValue) {}
    
        virtual void get(T &data) const                         
        {
           data = theData;
        }
    
        virtual void set(const T &data)     
        {
          theData = data; 
        }
    
      protected:
        T  theData;
      };
    
    /** The ugly macro version */
    #define TEMPLATE_BUCKETT(T) \
    class BucketT##T \
    { \
      public: \
    explicit BucketT##T(const T &initValue) : theData(initValue) {} \
        virtual void get(T &data) const \
        { \
           data = theData; \
        } \
        virtual void set(const T &data) \
        { \
          theData = data; \
        } \
      protected: \
        T  theData; \
    }
    
    /** Use the preprocessor to make a BucketT for int */
    TEMPLATE_BUCKETT(int);
    
    /** Use the preprocessor to make a BucketT for unsigned char */
    typedef unsigned char UINT8; /* make a typedef as the macro wont accept spaces! */
    TEMPLATE_BUCKETT(UINT8);
    
    void function(void)
    {
      /* Use the original class */
      BucketT<int> * myIntBucket;
      myIntBucket = new BucketT<int>(1);
      myIntBucket->set(10);
      delete myIntBucket;
    
      /* Use the macro generated class */
      BucketTint * myNewIntBucket;
      myNewIntBucket = new BucketTint(1);
      myNewIntBucket->set(10);
      delete myNewIntBucket;
    }
    


  • Advertisement
Advertisement