Wor*_*der 5 c++ dynamic-cast typeid typeinfo
有没有办法从两个const ::std::type_info对象中确定,让我们命名它们,B以及DD 描述的类型是否从类型 B 派生?
我问是因为我想删除我得到的对象的类型,但稍后能够检查它是否可以安全地提升。
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
}
Run Code Online (Sandbox Code Playgroud)
我希望能够像这样使用它:
class Base {};
class Derived : Base {};
Derived d;
store(d);
// ....
load<Base>();
Run Code Online (Sandbox Code Playgroud)
因此,只对 typeid 使用相等比较是不合适的。我很确定这可能以类似于 dynamic_cast 可以解决这个问题的方式成为可能。我想要的是,在每种情况下D&都可以指定B&允许 B 作为 - 的类型参数load()-D当时不知道。
我找到了一种方法让编译器和内部机制为我解决这个问题。我对交叉编译没有问题,在这种情况下::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();
}
}
Run Code Online (Sandbox Code Playgroud)
您所要做的就是将以下行添加到存储操作中:
dataThrow = throwing<D>;
Run Code Online (Sandbox Code Playgroud)
这是如何运作的?它利用了异常及其捕获方式。请注意,这使得poly_load“很多”?比简单load函数慢,因此我将保留两者。
D*C++ 表示,当抛出类型异常时,您可以使用 catch 子句捕获该异常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();
}
Run Code Online (Sandbox Code Playgroud)