Using Type-Erasure to store heterogenous properties
Ξ April 5th, 2012 | → 0 Comments |
∇ Uncategorized | ∇ |
The objective was to implement a Property class composed of a key and a value. The class is designed to store heterogenous data, implemeting a non-template class to allow storing properties in a standard container.
Property p("zero", 0),
auto key = p.key();
auto value = p.value< int >();
auto tname = p.type();
Let’s start over with the simple stuff: the class declaration and some public types.
class Property
{
public: // public types
typedef std::string key_t;
typedef std::string type_t;
To provide internal storage for the property value, define a Placeholder abstract class.
private:
class Placeholder
{
public:
Placeholder(const key_t& key) : key_(key) {}
virtual ~Placeholder() {};
virtual key_t key() { return key_; }
virtual type_t type() const = 0;
private:
key_t key_;
};
The Property class will store a pointer to Placeholder base class. This class provides for type-erasure since it does not mention the actual value type. The value is stored in the derived templated PlaceHolderStorage class.
template < typename T >
class PlaceholderStorage : public Placeholder
{
public:
PlaceholderStorage(const key_t& key, const T& value):
Placeholder(key), value_(value)
{}
virtual ~PlaceholderStorage() {}
virtual type_t type() const
{
return typename_of< T >();
};
virtual const T& value()
{
return value_;
}
private:
T value_;
};
The default constructor of property created an integer value 0 and “default” as key. Default construction is only available to allow for usage with map standard container. Construction is also enabled by a template with the type of the storage data.
public:
Property() :
property_( new PlaceholderStorage< int >("default", 0) )
{}
template < typename T >
Property(const key_t& key, const T& value) :
property_( new PlaceholderStorage< T >(key, value) )
{}
The Property allows access to the key and to the value. Access to the value requires a template type. A PropertyTypeInvalid exception is thrown if the requested type is not according to the stored value.
public:
key_t key() const
{
return property_->key();
}
type_t type() const
{
return property_->type();
}
template < typename T >
T value() const
{
PlaceholderStorage< T > *derived
= dynamic_cast<
PlaceholderStorage< T >* >(property_.get());
if(derived == 0x0)
throw PropertyTypeInvalid(
std::string("Invalid property type, accessing \"")
+ typename_of< T >()
+ "\" value, but type is \""
+ property_->type() + "\"");
return derived->value();
}
Internally, the Property stores the Placeholder for the data in a shared pointer.
private:
std::shared_ptr< Placeholder > property_;
};
To access the complete example, access abyss source code.


