CV - Projects - Snippets - Contact

Typeless Variables

AnyExample.cpp
  1. // Create and initialize 2 int type variables
  2. Value<int> int1(20);
  3. Value<int> int2(30);
  4.  
  5. // Obtain pointers to the previously created variables
  6. Any* any1 = &int1;
  7. Any* any2 = &int2;
  8.  
  9. // Assign an int type value to int2 (through any2)
  10. any2->set<int>(50);
  11.  
  12. // Assign the value of int2 to int1 (through the anonymous Any type)
  13. any1->copy(*any2);
  14. // Create a new Any containing the type and value of any2
  15. Any* any3 = any2->clone();
  16.  
  17. // Create and initialize a string type variable
  18. Value<std::string> string1("Text");
  19. // Set the value directly through the dereference operator which is part of Value<T>
  20. *string1 = "Testing";
  21.  
  22. // This will throw an exception due to incompatible types
  23. any1->copy(string1);

Typeless variables have many uses in c++.
In particular they have interesting uses in implementing:
  • Game object properties system
  • Serializable data for configuration or networking
  • Sharing, holding and queueing any data in a threaded environment

This particular implementation uses templates for accessing and setting data.
The Any class allows the data to be copied or cloned without knowing the underlaying type.
The Value class is an implementation of Any and serves as a container for all types that implement operator= and a copy constructor.
Type-safety is handled at run-time through the use of exceptions.

The concept can also easily be extending using the factory pattern and a type database to create truly anonymous types at run-time.
For example, I've utilized these anonymous variables to serialize complete classes and trees of data across the network.

On the right side there's a snippet that shows how my implementation of typeless variables is used. Below you can find the actual implementation of typeless variables (press 'Show' to display the source code).


Any.h
  1. #ifndef UTILS_Any_H
  2. #define UTILS_Any_H
  3.  
  4. #include <typeinfo>
  5. #include <string>
  6.  
  7. namespace Utils
  8. {
  9.   class Any
  10.   {
  11.     friend Any;
  12.   public:
  13.     virtual ~Any() {}
  14.     // Constant during a single run-time, may vary across multiple runs
  15.     virtual const std::type_info& type() const = 0;
  16.     template <class T> bool isType() const;
  17.     // Getter/setter
  18.     template <class T> void set(const T& value);
  19.     template <class T> const T& get() const;
  20.     // Anonymous modifications
  21.     void copy(const Any& any);
  22.     virtual Any* clone() const = 0;
  23.   protected:
  24.     Any() {}
  25.     virtual void _set(void* value) = 0;
  26.     virtual void* _get() const = 0;
  27.   private:
  28.     // Disable implicit copying
  29.     Any(const Any&) {}
  30.     Any& operator=(const Any& any) { return *this; }
  31.   };
  32. }
  33.  
  34. #include "Any.inl"
  35.  
  36. #endif
Any.inl
  1. #include <exception>
  2.  
  3. namespace Utils
  4. {
  5.   template <class T> inline bool Any::isType() const
  6.   {
  7.     return (this->type() == typeid(T));
  8.   }
  9.  
  10.   template <class T> inline void Any::set(const T& value)
  11.   {
  12.     if (typeid(T) != this->type())
  13.       throw std::exception("Type mismatch in Any::set");
  14.     _set((void*)&value);
  15.   }
  16.  
  17.   template <class T> inline const T& Any::get() const
  18.   {
  19.     if (typeid(T) != this->type())
  20.       throw std::exception("Type mismatch in Any::get");
  21.     return *(const T*)this->_get();
  22.   }
  23.  
  24.   inline void Any::copy(const Any& any)
  25.   {
  26.     if (any.type() != this->type())
  27.       throw std::exception("Type mismatch in Any::copy");
  28.     this->_set(any._get());
  29.   }
  30. }
Value.h
  1. #ifndef UTILS_Value_H
  2. #define UTILS_Value_H
  3.  
  4. #include "Any.h"
  5.  
  6. namespace Utils
  7. {
  8.   template <class T> class Value : public Any
  9.   {
  10.   public:
  11.     Value() : mValue() {}
  12.     Value(T value) : mValue(value) {}
  13.     Value(const Any& any) { this->copy(any); }
  14.     // Implement Any
  15.     virtual const std::type_info& type() const { return typeid(T); }
  16.     virtual Any* clone() const;
  17.     // Some convenient access methods
  18.     inline T* operator->() { return &mValue; }
  19.     inline const T* operator->() const { return &mValue; }
  20.     inline T& operator*() { return mValue; }
  21.     inline const T& operator*() const { return mValue; }
  22.   protected:
  23.     T mValue;
  24.     // Implement any
  25.     virtual void _set(void* value);
  26.     virtual void* _get() const;
  27.   };
  28. }
  29.  
  30. #include "Value.inl"
  31.  
  32. #endif
Value.inl
  1. #include <assert.h>
  2.  
  3. namespace Utils
  4. {
  5.   template <class T> inline Any* Value<T>::clone() const
  6.   {
  7.     return new Value<T>(mValue);
  8.   }
  9.  
  10.   template <class T> inline void Value<T>::_set(void* value)
  11.   {
  12.     // Assumes type safety has been taken care of by Any::set
  13.     const T* pointer = (const T*)value;
  14.     mValue = *pointer;
  15.   }
  16.  
  17.   template <class T> inline void* Value<T>::_get() const
  18.   {
  19.     // Assumes type safety has been taken care of by Any::get
  20.     return (void*)&mValue;
  21.   }
  22. }