C++ 如何使用任意数量的(编译时确定的)容器创建内存池?
我有一个内存池,看起来是这样的:C++ 如何使用任意数量的(编译时确定的)容器创建内存池?,c++,templates,c++11,variadic-templates,variadic,C++,Templates,C++11,Variadic Templates,Variadic,我有一个内存池,看起来是这样的: template<typename TreeType> class LeafMemoryPool { public: void stealNodes(TreeType& tree); Leaf* getNode(); private: std::vector<Leaf*> mLeafs; } 以上所有内容都应该能够在编译时确定。我能用C++模板魔术来解决这个问题吗?< /P> #include <
template<typename TreeType>
class LeafMemoryPool
{
public:
void stealNodes(TreeType& tree);
Leaf* getNode();
private:
std::vector<Leaf*> mLeafs;
}
以上所有内容都应该能够在编译时确定。我能用C++模板魔术来解决这个问题吗?< /P> <代码>
#include <tuple>
#include <vector>
#include <string>
template<typename... TreeTypes>
class MemoryPool
{
public:
// The template is only valid if the same type was declared
// in TreeTypes above
template<typename TreeType>
void stealNodes(TreeType& tree)
{
// Somehow need to access the right std::vector that
// stores TreeType::Leaf. This function will be called
// a lot, and needs to be determined at compile time
// for it to be useful.
using leaf_type = typename TreeType::Leaf;
using vec_type = std::vector<leaf_type>;
auto& pool = std::get<vec_type>(_leaves);
}
template<typename TreeType>
typename TreeType::Leaf* getNode()
{
using leaf_type = typename TreeType::Leaf;
using vec_type = std::vector<leaf_type>;
auto& pool = std::get<vec_type>(_leaves);
// pool is now a reference to your vector
}
private:
// One for each TreeType in TreeTypes.
// The leaf type can be deduced by
// typename TreeType::Leaf
std::tuple< std::vector<typename TreeTypes::Leaf> ... > _leaves;
};
#包括
#包括
模板
类内存池
{
公众:
//仅当声明了相同类型时,模板才有效
//在上面的三个字母中
模板
空心硬脂节点(树形和树形)
{
//需要访问正确的std::vector
//存储TreeType::Leaf。将调用此函数
//很多,需要在编译时确定
//为了让它有用。
使用leaf_type=typename树型::leaf;
使用vec_type=std::vector;
auto&pool=std::get(_leaves);
}
模板
typename树型::叶*getNode()
{
使用leaf_type=typename树型::leaf;
使用vec_type=std::vector;
auto&pool=std::get(_leaves);
//池现在是对向量的引用
}
私人:
//树型中每个树型一个。
//叶片类型可通过以下公式推断:
//typename树型::叶
std::tuple是的,可以这样做。我将给你们一个简化版的类的解决方案。您应该能够为您的类简单地调整此解决方案。按照gcc 6.1.1进行测试
#include <vector>
class A {};
class B {};
class C {};
template<typename ...Args> class pool;
template<typename firstArg, typename ...Args>
class pool<firstArg, Args...> : public pool<Args...> {
public:
using pool<Args...>::stealNodes;
void stealNodes(firstArg &tree)
{
}
private:
std::vector<firstArg *> leafs;
};
template<> class pool<> {
public:
void stealNodes(); // Undefined
};
void foo()
{
pool<A, B, C> pool;
A a;
B b;
C c;
pool.stealNodes(a);
pool.stealNodes(b);
pool.stealNodes(c);
}
#包括
A类{};
B类{};
C类{};
模板类池;
模板
类池:公共池{
公众:
使用pool::stealNodes;
void stealNodes(firstArg和tree)
{
}
私人:
std::向量叶;
};
模板类池{
公众:
void stealNodes();//未定义
};
void foo()
{
游泳池;
A A;
B B;
C C;
池.硬脂节点(a);
硬脂节点池(b);
池.硬脂节点(c);
}
std::tuple将使用MemoryPools=std::tuple执行类似于模板的操作代码>。两个问题:(1)是否会在编译时绑定auto&pool
,或者是否完成了任何运行时查找?(2) 将动态对象存储在std::tuple
?1)编译时,2)一点问题也没有。答案很好,但@Sam的解决方案使stealNodes
成为一个非模板函数,它提供了更好的错误消息,更好地处理派生的树型体。@yack我不知道。我认为在调试器中两者都会看起来同样可怕。对于简单的情况,只要它是广泛的。至少这只是一个层次的推导深度。如果添加了其他数据成员/非虚拟函数怎么办?这个相互派生的版本很快就会成为一场噩梦。我已经读了好几遍了,但我仍然不确定到底发生了什么。子类化的目的是什么?以及pool.stealNodes(a)
如何正确地确定“正确的”std::vector
?@pingul操作符重载。Sam,getNode
有点棘手,您可能需要将其包括在内。可能是最派生的pool
助手,将您的类型重命名为pool\u impl
,并给pool
一个模板typename T::Leaf*getNode(){return getNode(tag);}
?其中pool\u impl
实现getNode(tag)
?哦,为了清理它,我将继承从实现中分离出来。类似于struct simple\u pool
(带有向量和stealNodes函数等)和struct pool:simple\u pool,pool{使用simple_pool::stealNodes;使用pool::stealNodes;
只是因为错误消息在大多数编译器中更容易阅读。@Yakk我尝试过实现您的建议,但我对模板的了解似乎有点有限。如果可能,请提供一个独立的示例。正如@Yakk前面提到的,getNode
将很难实现。我通过稍微将函数更改为void getNode(typename firstArg::Leaf*)来解决这个问题
相反,在这种情况下,运算符重载也会起到一些作用。是否会选择另一种解决方案/更好?据我所知,这是有道理的,因为我必须以某种方式声明我正在寻找的叶的类型。
#include <vector>
class A {};
class B {};
class C {};
template<typename ...Args> class pool;
template<typename firstArg, typename ...Args>
class pool<firstArg, Args...> : public pool<Args...> {
public:
using pool<Args...>::stealNodes;
void stealNodes(firstArg &tree)
{
}
private:
std::vector<firstArg *> leafs;
};
template<> class pool<> {
public:
void stealNodes(); // Undefined
};
void foo()
{
pool<A, B, C> pool;
A a;
B b;
C c;
pool.stealNodes(a);
pool.stealNodes(b);
pool.stealNodes(c);
}