C ++模板问题

时间:2009-10-20 15:54:01

标签: c++ metaprogramming

我已经定义了一个通用的树节点类,如下所示:

template<class DataType>
class GenericNode
{
public:
    GenericNode() {}

    GenericNode(const DataType & inData) : mData(inData){}

    const DataType & data() const
    { return mData; }

    void setData(const DataType & inData)
    { mData = inData; }

    size_t getChildCount() const
    { return mChildren.size(); }

    const GenericNode * getChild(size_t idx) const
    { return mChildren[idx]; }

    GenericNode * getChild(size_t idx)
    { return mChildren[idx]; }

    void addChild(GenericNode * inItem)
    { mChildren.push_back(inItem); }

private:
    DataType mData;
    typedef std::vector<GenericNode*> Children;
    Children mChildren;
};
typedef GenericNode<std::string> TreeItemInfo;

我想通过使子指针类型可自定义来使其更通用。例如,允许使用智能指针类型。天真的我试过这个:

template<class DataType, class ChildPtr>
class GenericNode
{
public:
    GenericNode() {}

    GenericNode(const DataType & inData) : mData(inData){}

    const DataType & data() const
    { return mData; }

    void setData(const DataType & inData)
    { mData = inData; }

    size_t getChildCount() const
    { return mChildren.size(); }

    const ChildPtr getChild(size_t idx) const
    { return mChildren[idx]; }

    ChildPtr getChild(size_t idx)
    { return mChildren[idx]; }

    void addChild(ChildPtr inItem)
    { mChildren.push_back(inItem); }

private:
    DataType mData;
    typedef std::vector<ChildPtr> Children;
    Children mChildren;
};

typedef GenericNode<std::string, GenericNode<std::string > * > TreeItemInfo;

然而,这当然不起作用,因为我需要为第二个参数等第二个参数指定第二个参数......进入永恒。

有没有办法解决这个难题?

修改

我找到了一个基于@Asaf答案的解决方案。对于那些感兴趣的人,下面是一个完整的代码示例(欢迎提出意见)。

EDIT2

我修改了界面,以便始终使用外部原始指针。

#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <assert.h>


template <class PointeeType>
struct NormalPointerPolicy
{
    typedef PointeeType* PointerType;

    static PointeeType* getRaw(PointerType p)
    {
        return p;
    }
};

template <class PointeeType>
struct SharedPointerPolicy
{
    typedef boost::shared_ptr<PointeeType> PointerType;

    static PointeeType* getRaw(PointerType p)
    {
        return p.get();
    }
};


template <class DataType, template <class> class PointerPolicy>
class GenericNode
{
public:    
    GenericNode() { }

    GenericNode(const DataType & inData) : mData(inData) { }

    typedef GenericNode<DataType, PointerPolicy> This;

    typedef typename PointerPolicy<This>::PointerType ChildPtr;

    const This * getChild(size_t idx) const
    { return PointerPolicy<This>::getRaw(mChildren[idx]); }

    This * getChild(size_t idx)
    { return PointerPolicy<This>::getRaw(mChildren[idx]); }

    void addChild(This * inItem)
    { 
        ChildPtr item(inItem);
        mChildren.push_back(item);
    }

    const DataType & data() const
    { return mData; }

    void setData(const DataType & inData)
    { mData = inData; }

private:
    DataType mData;
    std::vector<ChildPtr> mChildren;
};

typedef GenericNode<std::string, NormalPointerPolicy> SimpleNode;
typedef GenericNode<std::string, SharedPointerPolicy> SmartNode;


int main()
{
    SimpleNode simpleNode;
    simpleNode.addChild(new SimpleNode("test1"));
    simpleNode.addChild(new SimpleNode("test2"));
    SimpleNode * a = simpleNode.getChild(0);
    assert(a->data() == "test1");
    const SimpleNode * b = static_cast<const SimpleNode>(simpleNode).getChild(1);
    assert(b->data() == "test2");

    SmartNode smartNode;
    smartNode.addChild(new SmartNode("test3"));
    smartNode.addChild(new SmartNode("test4"));
    SmartNode * c = smartNode.getChild(0);
    assert(c->data() == "test3");
    SmartNode * d = static_cast<const SmartNode>(smartNode).getChild(1);
    assert(d->data() == "test4");
    return 0;
}

1 个答案:

答案 0 :(得分:2)

不是你看待它的方式。你应该在这里结合某种继承。 试试这个,例如:

template <class PointeeType>
struct NormalPointerPolicy
{
    typedef PointeeType* PointerType;
};

template <class PointeeType>
struct SmartPointerPolicy
{
    typedef MySmartPtrClass<PointeeType> PointerType;
};

template <class DataType>
class BaseGenericNode
{
public:
    BaseGenericNode() {}

    BaseGenericNode(const DataType & inData) : mData(inData){}

    const DataType & data() const
    { return mData; }

    void setData(const DataType & inData)
    { mData = inData; }

protected:
    DataType mData;

};

template <class DataType, template <class> class PointerPolicy>
class GenericNode : public BaseGenericNode<DataType>
{
    typedef typename PointerPolicy<BaseGenericNode<DataType> >::PointerType ChildPtr;

private:
    typedef std::vector<ChildPtr> Children;
    Children mChildren;
};

GenericNode是实际的节点类型,它包含基类型“BaseGenericNode” 基类型保存实际数据(及其相关功能),派生类保存到其他节点的链接 指针的实际外观有2个模板策略类,你可以这样使用它们:

GenericNode<int, NormalPointerPolicy> instance;
GenericNode<int, SmartPointerPolicy> instance;

这个实现的问题(或优点?)是一个带有一种指针的节点,可以保存带有另一种指针的子节点。