如何创建具有任意数量(编译时确定)容器的内存池?

时间:2016-06-23 17:42:01

标签: c++ templates c++11 variadic-templates variadic

我有一个看起来像这样的内存池:

template<typename TreeType>
class LeafMemoryPool
{
public:
    void stealNodes(TreeType& tree);
    Leaf* getNode();
private:
    std::vector<Leaf*> mLeafs;
}

在我的程序中,我有不同的TreeType,如FloatTreeVec3Tree,我为每种树类型创建了一个内存池。然而,传递这些有点烦人,我更喜欢一个处理所有不同类型的内存池。此外,我可能需要在将来添加其他类型,我希望它尽可能地动态。这是可以使用可变参数模板完成的吗?我之前从未使用过它们,我不知道这是否可以用于它们。

我想到的场景可以用伪代码编写为

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.
    }

    template<typename TreeType>
    typename TreeType::Leaf* getNode();
private:
    // One for each TreeType in TreeTypes.
    // The leaf type can be deduced by
    // typename TreeType::Leaf
    std::vector<LeafArg1*> mLeafsForArg1;
    std::vector<LeafArg2*> mLeafsForArg2;
    ...
}

以上所有内容都应该能够在编译时确定。我可以用一些C ++模板魔术来解决这个问题吗?

2 个答案:

答案 0 :(得分:3)

是的,可以这样做。我将为您提供一个简化版课程的解决方案。您应该能够为您的班级轻松调整此解决方案。用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);
}

答案 1 :(得分:1)

#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;
};