【发布时间】:2021-03-23 13:51:53
【问题描述】:
我和我的队友正在做一项学校作业,我们在尝试保存值时遇到了一些麻烦。 我 100% 知道在代码中做的一些事情不是正常的做事方式,还有更好的方法,但部分作业是使用课堂上教授的概念。
问题:
我有一个火车课程,我想将它分配给一个平台,以便我知道平台上是否有火车。
template<typename T>
class Train
{
public:
//Some constructors, getters and other stuff
private:
std::string reg_nr_;
}
因为 Train 是一个模板,所以有不同的模板参数类,所以可以给它一个类型
struct IC3{};
struct IC4{};
要实例化一个 Train,它在 main 中通过以下方式完成,这也是它的预期使用方式。
Train<IC3> tester_train("testing_train");
Train<IC4> some_other_tester_train("some_other_tester_train");
Platform pl;
pl.train_arriving(tester_train);
pl.train_leaving(tester_train);
pl.train_arriving(some_other_tester_train);
class Platform
{
public:
using Trains = std::variant<TrainWrapper<Train<Arriva>>, TrainWrapper<Train<IC3>>, TrainWrapper<Train<IC4>>>;
template<typename U>
void train_arriving(U& t)
{
train_ = TrainWrapper<U>{ u };
}
void train_leaving()
{
train_ = ???????; //Should be set to nothing
}
private:
Trains train_;
}
template<typename T>
struct TrainWrapper
{
T& t;
};
现在是问题的真正部分。 我有一个 Train 模板类,它接受一个参数并将 Train 转换为不兼容的不同类型。这就提出了一个问题,即能够将这些不同的列车类型传递到平台并保存它们。 为了解决不同类型的不同传递问题,使用了 std::variant。这带来了一个新问题,即无法轻松检索数据,这就是使用 TrainWrapper 的原因,以便将 Train 存储在通用类型中。
修改变体(最后问我们的老师)我的队友和我到达了平台中看到的Trains 表达式。我们知道一个事实(使用局部变量),我们能够将 TrainWrapper 保存在 Trains 对象中。然而,我们的问题是我们希望能够改变平台上的火车。因此,我们认为指针将是前进的方向,但这样做会遇到转换错误,例如:Error C2440 '=': cannot convert from 'TrainWrapper<Train<Arriva>>' to 'Platform::Trains *'。我们尝试了一堆不同的指针变体,但总是一样的转换错误。
所以我们的问题或多或少是:我们如何才能在平台上保存 Train 以便我们能够再次将其删除?
【问题讨论】:
-
有什么理由避免动态多态性?也就是说,要为所有列车提供一个基类并从中派生特定类型的列车(
IC3、IC4等)? -
随着训练班数的增加,您会为每个模板获得一个新实例,该实例将非常快速地增长您的二进制文件,而无需任何需要。如果您有一个代表任何类型火车的基类并提供可以由您的“平台”使用的接口,它看起来会更干净。拥有完全不相关的类并使用 std::visit 可能是一种解决方案,但会带来更大的二进制文件的成本。并且 std::visit 可能比 vtable 访问慢得多,有时例如gcc 在运行时为 std::visible 生成跳转表。
-
我知道如果我们使用多态性,这个问题可能不会存在。不幸的是,这并不是本课程真正关注的重点(尽管早期课程已经涵盖了很多内容),而是关注模板以及如何在编译期间实现某些目标。所以这样做的原因只是为了表明对课程中教授的概念的理解。在我们的项目报告中,我们被允许写“我们知道这对这个和这个原因是不好的”,所以这是一个不好的解决方案不是问题
-
什么是
TrainWrapper?u来自哪里?怎么会有两个签名相同的train_arriving方法? -
@Eljay
TrainWrapper只是应该包装我们的Train对象,以便更容易使用std::visit。U应该是我们的论点。我盲目地承认我们并不完全确定参数应该是U或类似Train<U>或其他的东西。两个相同的train_arriving是一个类型。一个应该是train_leaving。这已在我的帖子中修复。
标签: c++ pointers templates wrapper variant