【发布时间】:2018-10-06 10:45:25
【问题描述】:
我有一个存储抽象类的一些对象的容器类。在某些部分,程序需要将这些对象作为实现类来获取。我写了一个通用的 get 函数,但它必须遍历所有存储的对象,这会花费很多时间。据我所知,容器只有一个类型的对象,我想在编译时解决这个问题,但不想手动为每种类型创建自己的成员。
目前我没有遇到“浪费”运行时的问题,但我想学习如何解决这个问题。
我目前的实现:
#include <iostream>
#include <list>
class Abstract
{
public:
virtual void update() = 0;
};
class ImplA : public Abstract
{
public:
void update() {std::cout << "implA" << std::endl;}
};
class ImplB : public Abstract
{
public:
void update() {std::cout << "implB" << std::endl;}
};
class Container
{
public:
Container(){
content.push_back(new ImplA);
content.push_back(new ImplB);
}
void update() {
for (Abstract* obj : content)
obj->update();
}
template<typename T> T* get() const {
for (Abstract* obj : content) {
if(dynamic_cast<T*>(obj) != nullptr)
return dynamic_cast<T*>(obj);
}
return nullptr;
}
private:
std::list<Abstract*> content;
};
int main()
{
Container* container = new Container();
container->get<ImplA>()->update();
container->get<ImplB>()->update();
return 0;
}
我对如何解决这个问题的想法:
- 为每种类型创建自己的成员并获取函数
- 不要使用列表,而是使用映射并使用 typeinfo.name 作为键(但这是一个运行时解决方案,是个坏主意)
- 实现类型列表(例如枚举类型 {implA, implB})并将其用作映射键。在这里,我必须为每种类型创建一个新条目。
- 使用诸如编译时映射之类的东西,它可以使用类型作为键。
提前致谢!
【问题讨论】:
-
也许你可以做一些CRTP诡计,以避免
dynamic_casts并用static_casts替换它们,这将在编译时解决。 -
我记得我们一直在使用
enum和某种 X macros 解决类似的情况,框架实现相当复杂,团队中的新开发人员学习曲线非常陡峭正确实现新类型(声明类、添加新枚举值、添加宏调用以实现getType()函数等)。我真的会考虑是否值得克服您面临的这种小的运行时开销。 -
@OP,是否总是所有注册都在同一个地方(
Container的构造函数在这里)?如果不是,那会使解决方案变得更加复杂,因为它们需要在链接时而不是编译时进行聚合。 -
@Quentin 是的,Container 的构造函数将始终创建所有对象。
标签: c++ templates compile-time