【发布时间】:2019-01-03 14:13:32
【问题描述】:
详情见下方代码,但底层场景如下。我有一个容器(一个会话),我可以将对象放入其中并从中取出。
类似于:
std::shared_ptr<Tiger> t = ...;
session.store("tigers/1", t);
std::shared_ptr<Tiger> t2 = session.load<Tiger>("tigers/1");
两个函数都定义为:
class Session {
template<class T>
void store(std::string id, std::shared_ptr<T> instance);
template<class T>
std::shared_ptr<T> load(std::string id);
}
请注意,会话可以存储异构类型,但在 store 和 load 时间我静态知道变量的类型是什么。
我的问题是我遇到了这样一种情况,即用户想要将Tiger 放入会话中,但改为检查基本类型。例如:
session.load<Animal>("tigers/1");
现在,我在会话中有效地将数据存储为void*,并使用reinterpret_cast 将它们恢复为用户提供的类型。这... 工作,只要一切都是微不足道的,但是当我们遇到稍微复杂的情况时,我们就会遇到问题。
这是演示我的问题的完整代码:
struct Animal
{
virtual void Pet() const = 0;
};
struct IJumpable
{
virtual void Jump() const = 0;
};
struct Tiger : Animal, IJumpable
{
void Pet() const override
{
std::cout << "Pet\n";
}
void Jump() const override
{
std::cout << "Jump\n";
}
};
int main()
{
auto cat = std::make_shared<Tiger>();
// how the data is stored inside the session
auto any_ptr = std::static_pointer_cast<void>(cat);
// how we get the data out of the session
auto namable = std::static_pointer_cast<IJumpable>(any_ptr);
namable->Jump();
std::cout << std::endl;
}
如果您运行此代码,您会看到它运行,但它不是调用Jump,而是调用Pet。我知道这是因为使用了错误的虚拟方法表,因为我在 `void* 上有效地调用了reinterpret_cast。
我的问题是在 C++ 中是否有处理这种情况的好方法。我环顾四周,没有看到任何符合我需要的东西。
我发现的有关异构容器的所有内容都假定为共享基类,而我没有也不想这样做。这可能吗?
【问题讨论】:
-
确定在
Session类中,您将只存储Animal的基本类型吗? -
如果你事先知道你存储的类型,也许你想看看 std::variant。
-
存储类型是静态已知的吗?如果是这样,您可以使用
std::variant吗?如果没有,可以使用std::any吗? -
@KrzysiekKarbowiak 我不能使用
std::any,因为类型不匹配。auto cat = new Tiger(); auto any_ptr = std::any(cat); auto namable = std::any_cast<IJumpable*>(any_ptr);这将导致错误的演员表 -
我对存储类型很好,但我不知道如何 这样做或如何正确取出它。我想过使用 lambda 来捕获类型,但我不知道如何正确获取目标类型
标签: c++