【发布时间】:2018-07-26 02:11:43
【问题描述】:
假设我有一个名为 Pool 的容器类模板和一个名为 PoolObject 的抽象类
类模板Pool 允许用户创建一个包含特定类型池对象的池。例如:
template<class T, size_t pool_size>
Pool()
{
// assert that type T is derived from PoolObject
public:
int grab(){};
void release(int object_id){};
private:
std::array<T, pool_size> pool_members_;
}
现在假设我想创建几个不同的池来管理几个不同的对象类型。
class PoolObject1 : public PoolObject{};
class PoolObject2 : public PoolObject{};
class PoolObject3 : public PoolObject{};
class PoolObject4 : public PoolObject{};
Pool<PoolObject1, 100> pool_1;
Pool<PoolObject2, 100> pool_2;
Pool<PoolObject3, 100> pool_3;
Pool<PoolObject4, 100> pool_4;
现在假设我要创建一个用于获取池对象的工厂函数和一个用于释放池对象的销毁函数。一个简单的实现将包含一个 switch 语句来确定应该使用哪个池。
int factory(int object_type)
{
switch(object_type)
{
case 1:
return pool_1.grab();
case 2:
return pool_2.grab();
case 3:
return pool_3.grab();
case 4:
return pool_4.grab();
}
}
虽然简单,但我必须为在这些池上运行的任何方法实现相同的 case 语句。比如destroy方法。
void destroy(int object_type, int object_id)
{
switch(object_type)
{
case 1:
return pool_1.release(object_id);
case 2:
return pool_2.release(object_id);
case 3:
return pool_3.release(object_id);
case 4:
return pool_4.release(object_id);
}
}
随着定义的对象类型越多,switch 语句越长,管理和更新每个方法变得很麻烦。
一个更简单的解决方案是有一个查找表来获取有问题的池,然后调用适当的方法。
例如,我可以尝试将指向每个池的指针存储在一个数组中。
std::array<void*, 4> pool_ptrs =
{
&pool_1,
&pool_2,
&pool_3,
&pool_4
};
有了这个池指针数组,我现在可以重写我的工厂和销毁方法,如下所示:
int factory(int object_type)
{
return static_cast<Pool*>(pool_ptrs[object_id])->grab();
}
void destroy(int object_type, int object_id)
{
return static_cast<Pool*>(pool_ptrs[object_id])->destroy(object_id);
}
但是,此代码不会编译。编译器抱怨我的Pool* 缺少模板参数。
所以我明白为什么我的代码无法编译,但是,我不知道合适的解决方案是什么。我本质上想将类模板用作“抽象类”。我不想投射指向Pool<Object1, 100> 的指针或指向Pool<Object2, 100> 的指针,我只想投射指向Pool 的指针
所以我的问题是:你可以在指向不同模板类实例的指针之间进行转换吗?
【问题讨论】:
-
代替
switch语句和整数类型ID、模板和类型。而不是重载,模板特化或只是实例化。此外,请确保确实存在要解决的性能问题(以某种方式,例如池):measure. -
出于好奇,假设这不是学术练习,为什么不使用现有的经过验证的
Boost.Pool库? boost.org/doc/libs/1_67_0/libs/pool/doc/html/index.html -
@Cheersandhth.-Alf 我想我不明白你的评论。你能扩展更多吗?我假设我使用的模板不正确。
-
如果您对语言不够了解,为什么还要尝试像内存池这样的高级东西?首先对更常见的事情进行一些练习并阅读好书以正确学习语言是很有意义的。如果您的方法如此复杂,那么您可能会损害性能而不是改进它。拥有一个隐藏类型信息然后必须打开类型的工厂没有多大意义,所以在我看来整个方法是错误的。
-
尽可能避免发布伪代码。发布实际代码,简化。
template<class T, size_t pool_size> Pool()不是实际代码;我认为其余的也不是。其次,如果你想要多态,你必须启用某种类型的擦除。这可以是基于继承的或鸭式的; C++ 不强制Pool模板类型实例之间的关系。您可以根据需要添加一个;只需编写一个不依赖于模板参数的抽象接口并从中继承即可。
标签: c++ templates metaprogramming