Accessing Values in a Class Similar to boost::any

断了今生、忘了曾经 提交于 2019-12-07 16:12:23

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!