问题
I'm making a simple boost::any
-like class for educational purposes, but I can't figure out how to access the stored value. I can set the value perfectly, but when I try to access any member in the "holder" class the compiler just complains that the member wasn't found in the class it was derived from. I can't declare the members as virtual
because of the templates.
Here's the relevant code:
class Element
{
struct ValueStorageBase
{
};
template <typename Datatype>
struct ValueStorage: public ValueStorageBase
{
Datatype Value;
ValueStorage(Datatype InitialValue)
{
Value = InitialValue;
}
};
ValueStorageBase* StoredValue;
public:
template <typename Datatype>
Element(Datatype InitialValue)
{
StoredValue = new ValueStorage<Datatype>(InitialValue);
}
template <typename Datatype>
Datatype Get()
{
return StoredValue->Value; // Error: "struct Element::ValueStorageBase" has no member named "Value."
}
};
回答1:
It's fine to add virtual functions to templates- just the functions themselves cannot be templates. A templated class or struct can still have virtual functions just fine. You need to use the magic of dynamic_cast.
class Element
{
struct ValueStorageBase
{
virtual ~ValueStorageBase() {}
};
template <typename Datatype>
struct ValueStorage: public ValueStorageBase
{
Datatype Value;
ValueStorage(Datatype InitialValue)
{
Value = InitialValue;
}
};
ValueStorageBase* StoredValue;
public:
template <typename Datatype>
Element(Datatype InitialValue)
{
StoredValue = new ValueStorage<Datatype>(InitialValue);
}
template <typename Datatype>
Datatype Get()
{
if(ValueStorage<DataType>* ptr = dynamic_cast<ValueStorage<DataType>*>(StoredValue)) {
return ptr->Value;
else
throw std::runtime_error("Incorrect type!"); // Error: "struct Element::ValueStorageBase" has no member named "Value."
}
};
If you change Get to return a Datatype*
you can return NULL
instead of throwing. You also haven't handled the memory of the previous value of StoredValue
, but I'm leaving that up to you.
回答2:
You need to cast it to ValueStorage
first.
Also add virtual destructur to ValueStorageBase class, to have polymorphic class. Without it you can't runtime check if your casting is OK :).
After it you can write:
template <typename Datatype>
Datatype Element_cast()
{
//throw exception for a wrong cast
if(typeid(*StoredValue)!=typeid(ValueStorage<Datatype>) )
throw exception;
//we already checked, that our type casting is OK,
//So no need for dynamic_cast anymore
return static_cast<ValueStorage*> (StoredValue)->value;
}
来源:https://stackoverflow.com/questions/5004088/accessing-values-in-a-class-similar-to-boostany