代码之家  ›  专栏  ›  技术社区  ›  StackedCrooked

C++模板问题

  •  3
  • StackedCrooked  · 技术社区  · 16 年前

    我定义了一个这样的通用树节点类:

    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答案的解决方案。对于感兴趣的人,下面是完整的代码示例(欢迎评论)。

    编辑2

    我修改了接口,这样外部总是使用原始指针。

    #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 回复  |  直到 16 年前
        1
  •  2
  •   Asaf    16 年前

    不是你看的那样。你应该在这里结合一些继承。 尝试此操作,例如:

    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”。
    基类型保存实际数据(及其相关功能),派生类保存到其他节点的链接。
    有两个模板策略类用于说明指针的实际外观,您可以这样使用它们:

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

    问题(或优势?)这种实现是指具有一种指针的节点可以容纳具有另一种指针的子节点。