Can we determine at runtime if two search_types are closed?

Is there a way to determine from two objects const ::std::type_info, name them Band D, if the type described by D is derived from type B?

I ask because I want to erase the type of object that I receive, but later, to check if it can be safely promoted.

void* data;
const ::std::type_info* D;

template<typename D>
void store(D&& object)
{
    D = &typeid(object);
    data = ::std::addressof(object);
}

template<typename B>
B& load()
{
    // if(typeid(B) != (*D)) throw ::std::bad_cast{};
    return *reinterpret_cast<B*>(data); // <- also problematic
}

I want to use it like this:

class Base {};
class Derived : Base {};

Derived d;
store(d);
// ....
load<Base>();

Thus, it is not practical to use equality comparisons for types. I am sure that this may be possible in the same way that dynamic_cast can understand it. I want that in every case, when I D&could be assigned B&, letting B as an argument of type load()- without knowing Dat this time.

+4
5

. -, ::std::type_info .

typedef void (*throw_op)(void*);
throw_op dataThrow;

template<typename T>
[[ noreturn ]] void throwing(void* data)
{
    throw static_cast<T*>(data);
}
[[ noreturn ]] void bad_cast()
{
    throw ::std::bad_cast{};
}

template<typename B>
B& poly_load()
{
    if(data == nullptr)
        bad_cast();
    try {
        dataThrow(data);
    } catch (B* ptr) {
        return *ptr;
    } catch (...) {
        bad_cast();
    }
}

, , :

dataThrow = throwing<D>;

? , . , poly_load? , load, .

++ , D* catch-clause B*, B D.

:

struct Base {
    virtual ~Base() {}
    virtual void foo() = 0;
};

struct Derived : public virtual Base {
    void foo() override {
        ::std::cout << "Hello from Derived" << ::std::endl;
    }
};

int main() {
    Derived d{};
    store(d);

    // .....

    poly_load<Base>().foo();
}
+3

, type_info.

reinterpret_cast , .

Derived* d = get_derived();
Base* b = reinterpret_cast<Base*>(d);

( Base Derived, ).

5.2.10:

. prvalue v " cv T", static_cast< cv T*>(static_cast< cv void*>(v)). prvalue " T1" " T2" ( T1 T2 - , T2 , T1) .

static_cast dynamic_cast , , , void* ( ).

, , Boost . . boost::variant::polymorphic_get

+1

, dynamic_cast catch try. , bad_cast. , , , NULL. .

0

. :

class polymorphic_erasure {
    std::function< void() > throw_self;

public:
    template< typename static_type >
    polymorphic_erasure( static_type & o )
        : throw_self( [ & o ] { throw & o; } )
        {}

    polymorphic_erasure()
        : throw_self( [] { throw std::bad_cast(); } )
        {}

    template< typename want_type >
    want_type & get() const {
        try {
            throw_self();
        } catch ( want_type * result ) {
            return * result;
        } catch ( ... ) {}
        throw std::bad_cast();
    }
};

: http://coliru.stacked-crooked.com/a/a12114a210c77a45

, , get - dynamic_cast. RTTI . (, .) RTTI , polymorphic_erasure . : .

0

:

void* data;

class Wrapper{ virtual ~Wrapper()=0; };
template<typename T> class SpecificWrapper: public Wrapper {
    public:
        T* value;
        Wrapper(T* ptr): value(ptr){}
        ~Wrapper() {}
}

template<typename D>
void store(D&& object)
{
    Wrapper* wrapper = new SpecificWrapper<D>(&object);
    if(data!= ::std::nullptr)
        delete reinterpret_cast<Wrapper*>(data);
    data = (void*)wrapper;
}

template<typename B>
B& load()
{
    //always safe because we know type being correct
    Wrapper *w = reinterpret_cast<Wrapper*>(data);
    SpecificWrapper<B> * w1 = dynamic_cast<SpecificWrapper<B>>(w);

    if(w1==::std::nullptr) throw ::std::bad_cast{};

    return w1->value;
}

The idea is to use a wrapper type hierarchy to erase a type while storing type information. This way you can statically determine that the type of a variable data, even if it is declared as void*, is always a top-level class Wrapper, which allows you to always perform safe clicks. You have to be careful with the lifetime of the wrapper object, though ...

-1
source

All Articles